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