Definition of the G4MULTITHREADED flag

According to the application developer’s guide for version 10.6:

The compiler flag -DG4MULTITHREADED is automatically set when
building applications using GEANT4’s CMake (via GEANT4_USE_FILE)

Leaving alone the fact that the CMake variable for the Geant4 use file is Geant4_USE_FILE and not GEANT4_USE_FILE (CMake 3.13.3 complains about the case mismatch), in my system with 10.6.p02 compiled with working multithreading support (verified by the console output of example B1) the use file does not contain any reference to G4MULTITHREADED. In fact, including the use file and compiling with VERBOSE=1 the compiler invocations show no trace of the G4MULTITHREADED flag.

This is consistent with the fact that in my programs the sections guarded by #ifdef G4MULTITHREADED are not executed, until one Geant4 header is included. From that point on, the guarded sections are executed, so I guessed that probably the flag is defined in a header. Effectively, in G4GlobalConfig.hh I found such a definition.

Now, my questions are: am I doing something wrong or missing some point? If not, should the G4GlobalConfig.hh be included before any other G4 header in every file using G4 headers? If yes, do you think that the guide should be updated to reflect this (quite important) point, and also purged from the incorrect reference to a compiler flag set by GEANT4_USE_FILE?

Thanks.

1 Like

Apologies, this is an oversight in the manual which we’ll correct. G4MULTITHREADED is, as you’ve identified, no longer transmitted by -D flag but as a #define in G4GlobalConfig.hh. That’s because the availability of multithreading support in Geant4 is determined when building Geant4 itself. End applications may chose to use this or not.

Whilst you can #include "G4GlobalConfig.hh", it’s better to include the G4Types.hh or globals.hh headers as these are more generally useful (and are needed for any non-trivial code anyway). These always #include the config header, so the G4MULTITHREADED symbol will always be available.

@bmorgan thanks for your reply, but I don’t understand your point. What is the advantage of defining the flag in a header rather than as a compiler flag? It still have to be checked in user’s code. Also, the flag does not express any intention by the end user of using MT or not; just the availability of it in the currently used G4 build. I guess that for choosing to use MT or not it should be combined with a user flag, e.g.:

#if defined(G4MULTITHREADED) && defined(USE_MT)
#include "G4MTRunManager.hh"
#else
#include "G4RunManager.hh"
#endif

and this would be the same when the flag is defined either as a compiler flag or in an included header. Is this correct? If yes, then in my opinion defining the flag in a header has only disadvantages:

  • One must remember to include globals.hh as the first header in all his headers…
  • …otherwise, the flag starts being defined as the first G4 header is included (since usually G4GlobalConfig.hh is indirectly included by almost all the G4 headers)…
  • … but it might happen that including just a select G4 header it does not get included, so the flag won’t be defined.

So I really don’t understand why the way of defining the MT flag has been changed (since the documentation refers to a compiler flag I guess that before it was like that, and that the new way of defining the flag in a header has been introduced at a certain point, right? If yes, in which version?).

Thanks for changing the official application developer’s guide; however, there are quite a few MT migration guides (see here for one that I believe is to be considered “official”) that still seems to refer to the flag definition as a compiler flag (i.e. no reference to including globals.hh), so I think that other people might keep being misguided in this aspect. I understand that it’s not G4 developers duty to keep any available guide on the web up to date, and that the official one is to be considered as the supreme reference; just saying that this problem might drag itself along quite for a few time.

Checks on G4MULTITHREADED occur in both Geant4 public headers and private translation units (.cc files) and so it must be defined/undefined to the same when building Geant4 itself and when compiling/linking against that build as it affects API and ABI. Transmitting this through a compiler flag that must be set correctly by clients of Geant4 is potentially error prone given this consistency requirement. A configure-time symbol in a header automatically enforces this correctly for all potential ways clients may compile/link against Geant4 and neither they nor us need worry the setting. It’s also a way to determine if a given build support MT with nothing more than a read or try compile check on this header.

Yes, that’s correct, the definition of the symbol only means “this build of Geant4 has support for multithreading”.

Yes, if you want your application to allow users to run it in multithreading or sequential modes, even when the MT capability is available, then that would be one way to do so. The examples show the simplest possible use case: always use MT if the used Geant4 supports it, otherwise sequential. It’s up to the application author to implement more complex use cases and associated checks/configuration.

The only difference between flag and header is that with the flag things will fall apart if for any reason the -DG4MULTITHREADED flag isn’t set correctly.

Or G4Types.hh, but then to use any Geant4 code you need to include at least one header. It then follows…

The Geant4 code itself should be (and it’s a bug if not) internally consistent here in #includeing globals.hh or G4Types.hh before any use of #defines. So any end application that includes A.N.Other Geant4 header will (modulo bugs) have G4MULTITHREADED defined or not after inclusion, and more importantly, correctly.

Thanks for the clarification. I still believe that a compiler flag is a safer choice: with the in-header definition if the very first lines in my translation unit are:

#ifdef G4MULTITHREADED
#include "G4MTRunManager.hh"
#else
#include "G4RunManager.hh"
#endif

as advertised in multiple guides then I’ll end up including G4RunManager.hh and from there on the MT flag will be defined, screwing the whole TU (as it actually happened to me). I think it’s far easier to enforce compiler and linker flags (CMake lets you do it in downstream applications in a way that is both consistent and transparent to the application developer by means of target_compile_options and target_link_options) than making sure that G4GlobalConfig.hh is directly or indirectly included before any #ifdef G4MULTITHREADED guard in every TU.

I’m afraid I disagree on the compiler flag, but you’re absolutely right that we should clarify the docs and guides on the use of multithreading/#includes, so will do for the upcoming release.

Whilst target_compile_options was evaluated for this use case and seems a good match, it was discounted as:

  1. It doesn’t solve the problem for non-CMake users (o.k. pkg-config, but it’s still a flag both us and the user has to set correctly)
  2. A flag (i.e. something that may or may not be there) shouldn’t be used for something like this that’s truly hard coded. A configure-time hard-coded #define/#undef pair is a very standard way of handling just this use case.

Geant4’s Geant4Config.cmake does provide the multithreaded component so the existence or not of multithreading support can either be required:

find_package(Geant4 REQUIRED multithreaded)

or optional and checked:

find_package(Geant4 REQUIRED)
if(Geant4_multithreaded_FOUND)
  # Just as an example
  target_compile_definitions(myApp PRIVATE G4MULTITHREADED)
endif()

But all cases, whether in cmake or not, without recourse to compiler flags are handled by

#include "G4Types.hh"

#ifdef G4MULTITHREADED
  mt_impl();
#else
  seq_impl();
#endif

which is no different to checking the version at compile time:

#include "G4Version.hh"

#if G4VERSION_NUMBER < 1070
  do_this();
#else
  do_that();
#endif

that is similarly something that’s hard-coded at build time.

Thanks again for the extra details. I think that maybe putting the flag in a header called something like G4MultiThreading.hh would be more intuitive. Your example about the version check definitely makes sense, since the name of the header to be included is really descriptive, while including G4Types.hh to make a check about multithreading sounds a bit odd at first sight; currently, it seems to me that including G4GlobalConfig.hh is more intuitive, since I’m going to make check about a global configuration of the G4 build, not about a data type.

Anyway I understood your point, and even if I still don’t think it’s the best way to handle these things I’d say that I’m fine with it. So thanks again for your time.

Hi

I am using example B1. To use it in multithread mode, I have included #include “G4Types.hh” and added following lines in the main()

#ifdef G4MULTITHREADED
G4MTRunManager* runManager = new G4MTRunManager;
runManager->SetNumberOfThreads(2*(G4Threading::G4GetNumberOfCores()));

#else
G4RunManager* runManager = new G4RunManager;
#endif

Then I build the code using -
cmake -DGEANT4_BUILD_MULTITHREADED=ON

then make -j10

but it is still taking same time to complete the same number of primaries. I m running the code on a computer having 20 threads.

Please let me know if I have to further modifications in the example B1 for MT.