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