Logo ROOT   6.16/01
Reference Guide
mt201_parallelHistoFill.C
Go to the documentation of this file.
1/// \file
2/// \ingroup tutorial_multicore
3/// \notebook
4/// Parallel fill of a histogram.
5/// This tutorial shows how a histogram can be filled in parallel
6/// with a multithreaded approach. The difference with the multiprocess case,
7/// see mp201, is that here we cannot count on the copy-on-write mechanism, but
8/// we rather need to protect the histogram resource with a TThreadedObject
9/// class. The result of the filling is monitored with the *SnapshotMerge*
10/// method. This method is not thread safe: in presence of ROOT histograms, the
11/// system will not crash but the result is not uniquely defined.
12///
13/// \macro_image
14/// \macro_code
15///
16/// \date January 2016
17/// \author Danilo Piparo
18
19const UInt_t poolSize = 4U;
20
21Int_t mt201_parallelHistoFill()
22{
24
25 // The concrete histogram instances are created in each thread
26 // lazily, i.e. only if a method is invoked.
27 ROOT::TThreadedObject<TH1F> ts_h("myHist", "Filled in parallel", 128, -8, 8);
28
29 // The function used to fill the histograms in each thread.
30 auto fillRandomHisto = [&](int seed = 0) {
31 TRandom3 rndm(seed);
32 // IMPORTANT!
33 // It is important to realise that a copy on the stack of the object we
34 // would like to perform operations on is the most efficient way of
35 // accessing it, in particular in presence of a tight loop like the one
36 // below where any overhead put on top of the Fill function call would
37 // have an impact.
38 auto histogram = ts_h.Get();
39 for (auto i : ROOT::TSeqI(1000000)) {
40 histogram->Fill(rndm.Gaus(0, 1));
41 }
42 };
43
44 // The seeds for the random number generators.
45 auto seeds = ROOT::TSeqI(1, poolSize + 1);
46
47 std::vector<std::thread> pool;
48
49 // A monitoring thread. This is here only to illustrate the functionality of
50 // the SnapshotMerge method.
51 // It allows "to spy" the multithreaded calculation without the need
52 // of interrupting it.
53 auto monitor = [&]() {
54 for (auto i : ROOT::TSeqI(5)) {
55 std::this_thread::sleep_for(std::chrono::duration<double, std::nano>(500));
56 auto h = ts_h.SnapshotMerge();
57 std::cout << "Entries for the snapshot " << h->GetEntries() << std::endl;
58 }
59 };
60 pool.emplace_back(monitor);
61
62 // The threads filling the histograms
63 for (auto seed : ROOT::TSeqI(seeds)) {
64 pool.emplace_back(fillRandomHisto, seed);
65 }
66
67 // Wait for the threads to finish
68 for (auto &&t : pool)
69 t.join();
70
71 // Merge the final result
72 auto sumRandomHisto = ts_h.Merge();
73
74 std::cout << "Entries for the total sum " << sumRandomHisto->GetEntries() << std::endl;
75
76 auto c = new TCanvas();
77 sumRandomHisto->DrawClone();
78 return 0;
79}
#define c(i)
Definition: RSha256.hxx:101
#define h(i)
Definition: RSha256.hxx:106
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
A pseudo container class which is a generator of indices.
Definition: TSeq.hxx:66
A wrapper to make object instances thread private, lazily.
The Canvas class.
Definition: TCanvas.h:31
Random number generator class based on M.
Definition: TRandom3.h:27
void EnableThreadSafety()
Enables the global mutex to make ROOT thread safe/aware.
Definition: TROOT.cxx:545
TSeq< int > TSeqI
Definition: TSeq.hxx:194