Strange behavior with MultiThreading

Hello all!

I try to realize multithreading and have a funny problem.

I collect information about generated secondary optical photons in an event in StackingAction::ClassifyNewTrack(const G4Track * aTrack) and collect information about detected optical photons in “CathodeSD::ProcessHits(G4Step* theStep, G4TouchableHistory*)” method. In last one I put information in a collection and parse contents of the collection in “EventAction::EndOfEventAction(const G4Event* evt)”.

In a single thread application I observe, for example, 1000 events when optical photons are produced in “ClassifyNewTrack” and 1000 times when some part of them are detected in “EndOfEventAction”.

In the multithread version of the same application (16 threads) I observe, for example, the same 1000 events when optical photons are produced in “ClassifyNewTrack” BUT only 1000/16 times when some information about them are found in collections in “EndOfEventAction”.

It looks like the sensitive detector works for ONE thread only.

What can be wrong??

I create all volumes in " DetectorConstruction::constructDetector()" method and after that define
the sensetive parts in ConstructSDandField()
{
G4cout << “DetectorConstruction::ConstructSDandField()” << G4endl;
//------------------------------------------------
// Sensitive detectors
//------------------------------------------------
G4SDManager* sdman = G4SDManager::GetSDMpointer();
sdman->SetVerboseLevel(1);

CathodeSD* theCathodeSD = new CathodeSD("sensitiveDetector_Cathode");
sdman->AddNewDetector(theCathodeSD);
SetSensitiveDetector(logicCathode, theCathodeSD);

}

The collection is created like this:
CathodeSD::CathodeSD(G4String name) : G4VSensitiveDetector(name), CatHitsCollection(NULL)
{
collectionName.insert(“CathHitsCollection”);
}

void CathodeSD::Initialize(G4HCofThisEvent* HCE)
{
static G4int HCID = -1;
CatHitsCollection = new ScOpticalHitsCollection(GetName(), collectionName[0]);
if (HCID < 0) { HCID = G4SDManager::GetSDMpointer()->GetCollectionID(collectionName[0]); }
HCE->AddHitsCollection(HCID, CatHitsCollection);
}

G4bool CathodeSD::ProcessHits(G4Step* theStep, G4TouchableHistory*)
{
//////////////////////////////////////////////////////////
// find the boundary process only once
//
static G4OpBoundaryProcess* boundary = NULL;
if (!boundary)
{
G4ProcessManager* pm = theStep->GetTrack()->GetDefinition()->GetProcessManager();
G4int nprocesses = pm->GetProcessListLength();
G4ProcessVector* pv = pm->GetProcessList();

	for (G4int i = 0; i<nprocesses; i++)
	{
		if ((*pv)[i]->GetProcessName() == "OpBoundary")
		{
			boundary = (G4OpBoundaryProcess*)(*pv)[i];
			break;
		}
	}
}

//////////////////////////////////////////////////////////
//
G4Track* track = theStep->GetTrack();
if((track->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition()) && (track->GetParentID()>0))
{


//Put put information about photon to collection
}

}

I am sorry for my stupid bug… but maybe it will help somebody else.

NEVER use STATIC variables in multithreading applications!

I recreated variables “G4int HCID” and “G4OpBoundaryProcess* boundary” as the class members
(they were originally STATIC variables in “CathodeSD::Initialize” and “CathodeSD::ProcessHits()” and now it works fine… I hope…

1 Like

Not stupid. Thread-safe software is very different from the way most of us learned to write code. It’s similar to how horribly different (and seemingly “badly written”) MPI code has to be in order to be efficient.

Geant4 provides a number of nice tools to help you with this. Moving statics to class data member is definitely the easiest solution for most user code. If you’re writing a class that itself is going to be shared across threads, you should look at G4ThreadLocal, G4ThreadLocalSingleton, G4Mutex, and related features.