Error related to multi-threading after upgraded to 11.2

Geant4 Version: 11.02
Operating System: MacOS Sonoma 14.2.1 on M2
Compiler/Version: Apple clang version 15.0.0
CMake Version: 3.28.0


I have a simple Geant4 application https://github.com/jintonic/gears/blob/master/gears.cc. It compiles and runs fine with Geant4.11.1.3. It compiles fine with 11.2 as well. But whenever I add /run/beamOn, I will get the following error messages many times at the end of the run. The output root file can still be generated without problem. I have a customized RunManager. Could you please provide some hints to help me pin down the cause of this error? Thanks!

Exception: [code: system:22] caught: mutex lock failed: Invalid argument
Non-critical error: mutex lock failure in ~G4Cache<P15G4HadFinalState>.
If the RunManagerKernel has been deleted, it failed to delete an allocated resource
and this destructor is being called after the statics were destroyed.
Exception: [code: system:22] caught: mutex lock failed: Invalid argument

Additional information:

https://github.com/jintonic/gears/blob/master/gears.cc#L520 gives the following message:

-------- WWWW ------- G4Exception-START -------- WWWW -------
*** G4Exception : Analysis_W001
      issued by : G4RootNtupleFileManager::SetNtupleMergingMode
Merging ntuples is not applicable in sequential application.
Setting was ignored.
*** This is just a warning message. ***
-------- WWWW -------- G4Exception-END --------- WWWW -------

So the application is regarded as a sequential application. Is it because my RunManager inherits G4RunManager instead of G4MTRunManager?

Extra information:

The application compiles and runs fine in x86_64 AlmaLinux 9.3.

I also face similar problem. Any suggestions? Thanks

Possibly. Have you tried inheriting from G4MTRunManager instead? However, I think that the functionality in the custom run manager would be better implemented in a separate class or even free function to sidestep that issue entirely.

Yes, that’s exactly right. In our experiment, I also wrote our own RunManager subclass, in particular to call /run/initialize before the first /run/beamOn, rather than all our users having to do that explicitly. To avoid your problem, but still be able to build and link both Sequential and MT, I wrote:

#if defined(G4MULTITHREADED)
#include "G4MTRunManager.hh"
#define G4RunManager_base G4MTRunManager
#else
#include "G4RunManager.hh"
#define G4RunManager_base G4RunManager
#endif

class CDMSRunManager : public G4RunManager_base {
public:
  CDMSRunManager() : G4RunManager_base() {;}
  virtual ~CDMSRunManager();
[...]

Happy new year! Sorry for the late reply. I am just back from the winter break.

@mkelsey, that’s a good solution! Glad to get help from CDMS folks :slight_smile:

@bmorgan, if I simply inherit from G4MTRunManager, I got the following error message:

-------- EEEE ------- G4Exception-START -------- EEEE -------
*** G4Exception : Run0123
      issued by : G4MTRunManager::SetUserAction()
For multi-threaded version, define G4VUserPrimaryGeneratorAction in G4VUserActionInitialization.
*** Fatal Exception *** core dump ***
 **** Track information is not available at this moment
 **** Step information is not available at this moment

-------- EEEE -------- G4Exception-END --------- EEEE -------

Now, the only reason for me to have a customized run manager is to define the /physics_lists/select macro command to facilitate the selection of reference physics list. I don’t have to do this as I can use the environment variable PHYSLIST to achieve the same thing. The problem is that many people do not know what is an environment variable. A macro command is more new-user-friendly than an environment variable.

It seems that I have to overwrite the G4RunManager::InitializePhysics() function to initialize a physics list chosen by an user through the macro command. Are there other possible solutions so that I don’t have to define this macro command inside the run manager?

Thanks,

Jing

It looks to me like you’re building an executable developed a long time ago. The message to focus on is:

For multi-threaded version, define G4VUserPrimaryGeneratorAction in G4VUserActionInitialization.

I will bet that in your main(), you still have the old style:

rm->SetUserAction(new PrimaryGeneratorAction);

You should look at the documentation for UserActions, and migrate your executable to have a separate UserActionInitialization class, where you instantiate PrimaryGenerator, EventAction, etc. That reorganization is required for MT running, but also works fine if you switch back to sequential.

You don’t need to do that with a custom RunManager. We have a similar, but even more complex system, where we can also select differnent optional physics on top of the basic physics list.

Our “PhysListFactory” singleton class instantiates its own Messenger for configuration. We instantiate the factory in main(), where it creates the desired basic physics list and registers it into the RunManager. If the user want a different list, we have a function that deletes the registered one, and registers the new one. It has additional functions that call “RegisterPhysics” as needed for the various optional components.

I did the standard way, that is, define G4VUserPrimaryGeneratorAction in G4VUserActionInitialization. But I got the following message. That’s why I went back and initialize everything in the customized run manager following the order suggested by the message.

-------- EEEE ------- G4Exception-START -------- EEEE -------
*** G4Exception : Run0041
      issued by : G4UserRunAction::G4UserRunAction()
 You are instantiating G4UserRunAction BEFORE your G4VUserPhysicsList is
instantiated and assigned to G4RunManager.
 Such an instantiation is prohibited. To fix this problem,
please make sure that your main() instantiates G4VUserPhysicsList AND
set it to G4RunManager before instantiating other user action classes
such as G4UserRunAction.
*** Fatal Exception *** core dump ***
 **** Track information is not available at this moment
 **** Step information is not available at this moment

-------- EEEE -------- G4Exception-END --------- EEEE -------

I guess the CDMS way is better, that is, let the default run manager to register a physics list and then use a macro command to delete the registered one and register a new one. Could you please share some code snippet to point me to the right direction?

Thanks,

Jing

Here’s what we do in our “main” (where plName below is passed in as an argument):

  runManager.StoreRandomNumberStatusToG4Event(1);

  // If no physics list provided, use the Geant4 default
  CDMSPhysListFactory::SetPhysicsList(plName);

  // Geometry, sources and controls (all owned by G4RunManager)
  runManager.SetUserInitialization(geo?geo:geo=new CDMSGeomConstructor);

  runManager.SetUserInitialization(act?act:act=new CDMSActionInitialization);

#ifdef G4VIS_USE
  if (!visManager) visManager = new G4VisExecutive("quiet");
  visManager->Initialize();
#endif

  // Configure command interface to include storing history buffer
  UImanager->SetMaxHistSize(10000);     // Should be larger than any macros

The order of registration is important: physics list, then geometry, then all the user actions. That last line isn’t important – we do it so we can store all the macro commands to our output ROOT file; it helps with reproducibility.

@mkelsey, thank you! Do you know which function to use to delete the old physics list?

We don’t delete it. Here’s the replacement code I wrote back in 2015:

  // Replace previously registered physics list
  G4RunManager* rm = G4RunManager::GetRunManager();

  // NOTE:  This causes memory leak, but previous list cannot be deleted!
  rm->SetUserInitialization(physics);

The function of interest would be G4RunManager::GetUserPhysicsList(), which returns a const pointer. I think my comment above is not actually correct – you certainly can delete a const pointer in C++, and we probably should. The right code would be (I think):

  delete rm->GetUserPhysicsList();
  rm->SetUserInitialization(physics);

This isn’t thread safe, but at the time it’s happening, only the master thread is active, so that’s not an issue.

I’ve just never bothered to mess with it, because it’s a tiny effect compared to all of the other memory usage in G4.

All right, here is my plan.

  1. do everything in the suggested order:
auto *run = G4RunManagerFactory::CreateRunManager();
run->SetUserInitialization(new FTFP_BERT(verbose));
run->SetUserInitialization(new Detector);
run->SetUserInitialization(new Action);
  1. create a messenger, in its SetNewValue function run
delete runman->GetUserPhysicsList();
G4PhysListFactory factory;
runman->SetUserInitialization(factory.ReferencePhysList());

The question is that how I can get the pointer to the existing run manager from the messenger class.

You can get the run manager anywhere in your code using G4RunManager::GetRunManager(). It’s a global singleton. See G4RunManager.hh.

@mkelsey, thanks. I am happy with this solution. But the mutex lock failed message given in my original post is still a mystery. Anyway, I’ll proceed to get rid of my customized run manager, and start to use the one given by G4RunManagerFactory. Best, Jing

I cannot delete runman->GetUserPhysicsList(); otherwise, I get the following when I run runman->SetUserInitialization(factory.ReferencePhysList()); Apparently, I delete too much stuff this way. @mkelsey, as you said, I can just live with a bit memory leak. But it would be great if I can achieve this in a clean way…

--- G4CoupledTransportation is used 
G4PhysicsListHelper::RegisterProcess  : No Process Manager for 

-------- EEEE ------- G4Exception-START -------- EEEE -------
*** G4Exception : Riun0110
      issued by : G4PhysicsListHelper::RegisterProcess   
No process manager
*** Fatal Exception *** core dump ***
 **** Track information is not available at this moment
 **** Step information is not available at this moment

-------- EEEE -------- G4Exception-END --------- EEEE -------

By the way, there is a typo in the message: Riun0110.