Clone master UI manager commands in worker threads

In my application I create some UI commands before the threads are spawn, so they are assigned to the UI manager for master thread. But some of these commands create user action classes, so they need to be executed in worker threads. I saw that commands in the command file are processed in the master thread and then forwarded to worker threads, so they are effectively execute for all threads. However, they have no effect since my custom commands are not present in UI managers of worker threads. So I wonder if it is possible to clone the master UI manager command into the worker UI managers.

I presume that your custom commands are encapsulated in a Messenger class? If so, then the Messenger class needs to be instantiated separately in each of the worker threads.

If the custom UI commands are tied to an action class (e.g., custom commands for your UserEventAction), or some other object that does things in your worker threads, then you can make the Messenger class a data member of that working object, and you’ll get a separate instance in each worker thread automatically.

If the Messenger class is “free standing”, then you can instantiate it as part of the worker-thread UserActionInitialization::Build() function.

@mkelsey thanks for the ideas, but none of them can work in my use case. I actually simplified the situation when describing my use case on the initial post; the real one is that the commands are created by the constructors of proxy global objects in plugin shared libraries that are loaded at the beginning of the execution; these commands create user action classes, so that the user can decide which user actions to use at runtime with simple UI commands. As such, they are not tied to a user action: they are encapsulated in a messenger that lives in the master thread (which is the only thread that exists when the commands are created).

But I think I found a way to fix my issue:

  1. create the commands as before, building also a list of commands as they are created;
  2. when the worker thread is initialized, search the commands in the UI manager of the master thread using the list (in order to separate my commands from standard G4 ones);
  3. create a copy of each command using the copy constructor and put it in the UI manager of the worker thread;
  4. remove the commands from master UI (since master thread should not create user actions).

I still have to figure out where to put each piece of code but from a first check putting it in the user action initialization it seems to work. Do you see nay pitfalls in this procedure? Thanks.

That means that those custom UI commands must be communicating back to your UserActionInitialization object to tell it what things to instantiate in its Build() action. If that’s the case, then you “shouldn’t” need them in the worker threads. Instead, they’d be setting flags in UserActionInitialization in the master thread. When the worker thread calls into UserActionInitialization::Build(), that function should be able to see those flag settings, and instantiate/register the requested action objects.

1 Like

I don’t think that what you propose will work. That commands are created by external plugin libraries which knows nothing about the main program loading them; they are aware only of singletons. In particular, commands know nothing about my user action initialization and thus cannot interact with it.

But I think I found an alternative way to implement your proposal: instead of creaating build commands, the plugins simply register build functions into singleton factories; the factories can be queried by my main function for the list of registered classes, and then the main can create the “build” commands that simply fills a list of user actions to be built which is a member of my user action initialization. The execution of the datacard will simply fill this list in the initialization action, and in the Build() function I can build all the classes in the list using the factories. With the needed adjustments it should work.

Thanks for your support, @mkelsey!

That sounds like the right approach! I will admit that I have not worked with plug-in libraries at all, so my perspective was coming from shared libraries and a self-contained executable. I’m glad I was able to at least point you in the right direction.

@mkelsey Sadly, the approach you proposed really don’t work, for a simple reason: in G4MTRunManagerKernel::StartThread the method G4UserActionInitialization::Build is called before the commands are processed (this happens in G4WorkerRunManager::DoWork). So when I build the user actions the list of actions to be built is empty. Since commands are executed after building the action initialization I really think that the only way to make them work is for them to actually build the actions, rather than simply registering them into a factory. I’m about to rework my code in this sense.