Help with G4Cache -- multiple instances per thread?

TL;DR: 1) Can G4Cache instances be used across multiple instances within a thread, or is it a thread-local singleton? 2) Can I initialize a data member reference using G4Cache::Get() in the constructor?


I’m working on reducing the memory footprint for meshed electric field models in the G4CMP library. My goal is to have one mesh per type of detector, shared across all threads, and all instances (detector volumes) within each thread.

My meshing object (G4CMPVMeshInterpolator base class) has huge arrays which are initialized during the construction and setup process (on the master thread), but during tracking there’s just a single G4int index for “last simplex used” that needs to be mutable. To support sharing a single instance, I read the documentation for using G4Cache, and modified my class thus:

  // Per-instance storage to remember last tetrahedron used
  mutable G4Cache<G4double> TetraIdxStore;
  G4double& TetraIdx;

In the base class constructor, I wrote:

  G4CMPVMeshInterpolator(const G4String& prefix)
    : TetraStart(-1), savePrefix(prefix), TetraIdx(TetraIdxStore.Get()) {;}

Unfortunately, when I try running, I get inconsistent results or segfaults. One example just now reports the error deep in a vector evaluation:

(gdb) bt
#0  0x00002aaaaaedd2f7 in std::_Bit_reference::operator bool (
    this=<optimized out>)
    at /sw/eb/sw/GCCcore/12.2.0/include/c++/12.2.0/bits/stl_bvector.h:96

where my TetraIdx index value is

(gdb) p TetraIdx
$2 = (G4double &) @0xc126e8: -1668109584

which is obviously nonsense (the index should run from 0 up to 1526086 for my test geometry).

I’ve probably got other problems that need fixing, but this is one I want to ask about. If I have multiple instances of the class, each one of which is shared across threads, does G4Cache::Get() return a unique reference for each instance, or is there just one reference per thread?


Geant4 Version: 10.07.p04
Operating System: CentOS7
Compiler/Version: GCC 12.2.0
CMake Version: CMake 3.24.3

The reference returned should be both unique per instance and unique per thread. If I understand correctly, there are N instances that hold a G4Cache instance constructed on the main thread, each of which is shared to the worker threads. That being the case, within each worker thread, each of the N instances will have a unique reference returned by G4Cache::Get(), all of which will be different from those on the other worker threads.

One thing I’m not quite clear on is the initialization and subsequent use of the variables:

How are these used or updated in the class in the main and worker threads? It feels like TetraIdx is duplicating TetraIdxStore but without the thread-unique protection.

So TetraIdx is just a reference – it’s initialized in the ctor’s initializer list to be to the reference returned by G4Cache::Get(). My intention is for this to be equivalent to the example in the documentation:

Since Get returns a reference to the cached object is possible to avoid to use Put to update the cache:

   void G4Class::bar() {
       //Get a reference to the thread-local value:
       G4double& local = fValue.Get();
       // Use local as in the original sequential code, cache is updated, without the need to use Put
       local++;
   }

instead of a local variable, it’s a class data member. Having spelled that out, I see that I am not properly initializing the value of TetraIdx, so I will fix that!

How are these used or updated in the class in the main and worker threads? It feels like TetraIdx is duplicating TetraIdxStore but without the thread-unique protection.

… And showing this to another pair of eyes has revealed that I’m entirely on the wrong track. You’re quite right, Ben. That constructor only gets called in the master thread. Therefore, TetraIdx only gets initialized the one master thread instance, and is not thread safe at all (as well as not being initialized).
I need a per-instance “setup” function, and TetraIdx can’t be a reference.

Thank you very much for the time, Ben.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.