Logo ROOT   6.16/01
Reference Guide
TTaskGroup.cxx
Go to the documentation of this file.
1// @(#)root/thread:$Id$
2// Author: Danilo Piparo August 2017
3
4/*************************************************************************
5 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "RConfigure.h"
13
14#include "ROOT/TTaskGroup.hxx"
15
16#ifdef R__USE_IMT
17#include "TROOT.h"
18#include "tbb/task_group.h"
19#include "tbb/task_arena.h"
20#endif
21
22#include <type_traits>
23
24/**
25\class ROOT::Experimental::TTaskGroup
26\ingroup Parallelism
27\brief A class to manage the asynchronous execution of work items.
28
29A TTaskGroup represents concurrent execution of a group of tasks.
30Tasks may be dynamically added to the group as it is executing.
31Nesting TTaskGroup instances may result in a runtime overhead.
32*/
33
34namespace ROOT {
35
36namespace Internal {
37
38#ifdef R__USE_IMT
39tbb::task_group *CastToTG(void* p) {
40 return (tbb::task_group *) p;
41}
42
43tbb::task_arena *CastToTA(void *p)
44{
45 return (tbb::task_arena *)p;
46}
47
48#endif
49
50} // namespace Internal
51
52namespace Experimental {
53
54using namespace ROOT::Internal;
55
56// in the constructor and destructor the casts are present in order to be able
57// to be independent from the runtime used.
58// This leaves the door open for other TTaskGroup implementations.
59
61{
62#ifdef R__USE_IMT
64 throw std::runtime_error("Implicit parallelism not enabled. Cannot instantiate a TTaskGroup.");
65 }
66 fTaskContainer = ((void *)new tbb::task_group());
67 fTaskArena = ((void *)new tbb::task_arena(ROOT::GetImplicitMTPoolSize()));
68#endif
69}
70
72{
73 *this = std::move(other);
74}
75
77{
78 fTaskContainer = other.fTaskContainer;
79 other.fTaskContainer = nullptr;
80 fTaskArena = other.fTaskArena;
81 fTaskArena = nullptr;
82 fCanRun.store(other.fCanRun);
83 return *this;
84}
85
87{
88#ifdef R__USE_IMT
89 if (!fTaskContainer)
90 return;
91 Wait();
93 delete CastToTA(fTaskArena);
94#endif
95}
96
97/////////////////////////////////////////////////////////////////////////////
98/// Run operation in the internal task arena to implement work isolation, i.e.
99/// prevent stealing of work items spawned by ancestors.
100void TTaskGroup::ExecuteInIsolation(const std::function<void(void)> &operation)
101{
102#ifdef R__USE_IMT
103 CastToTA(fTaskArena)->execute([&] { operation(); });
104#else
105 operation();
106#endif
107}
108
109/////////////////////////////////////////////////////////////////////////////
110/// Cancel all submitted tasks immediately.
112{
113#ifdef R__USE_IMT
114 fCanRun = false;
115 ExecuteInIsolation([&] { CastToTG(fTaskContainer)->cancel(); });
116 fCanRun = true;
117#endif
118}
119
120/////////////////////////////////////////////////////////////////////////////
121/// Add to the group an item of work which will be ran asynchronously.
122/// Adding many small items of work to the TTaskGroup is not efficient,
123/// unless they run for long enough. If the work to be done is little, look
124/// try to express nested parallelism or resort to other constructs such as
125/// the TThreadExecutor.
126/// Trying to add a work item to the group while it is in waiting state
127/// makes the method block.
128void TTaskGroup::Run(const std::function<void(void)> &closure)
129{
130#ifdef R__USE_IMT
131 while (!fCanRun)
132 /* empty */;
133
134 ExecuteInIsolation([&] { CastToTG(fTaskContainer)->run(closure); });
135#else
136 closure();
137#endif
138}
139
140/////////////////////////////////////////////////////////////////////////////
141/// Wait until all submitted items of work are completed. This method
142/// is blocking.
144{
145#ifdef R__USE_IMT
146 fCanRun = false;
147 ExecuteInIsolation([&] { CastToTG(fTaskContainer)->wait(); });
148 fCanRun = true;
149#endif
150}
151} // namespace Experimental
152} // namespace ROOT
A class to manage the asynchronous execution of work items.
Definition: TTaskGroup.hxx:21
void ExecuteInIsolation(const std::function< void(void)> &operation)
Run operation in the internal task arena to implement work isolation, i.e.
Definition: TTaskGroup.cxx:100
void Run(const std::function< void(void)> &closure)
Add to the group an item of work which will be ran asynchronously.
Definition: TTaskGroup.cxx:128
void Wait()
Wait until all submitted items of work are completed.
Definition: TTaskGroup.cxx:143
void Cancel()
Cancel all submitted tasks immediately.
Definition: TTaskGroup.cxx:111
TTaskGroup & operator=(TTaskGroup &&other)
Definition: TTaskGroup.cxx:76
std::atomic< bool > fCanRun
Definition: TTaskGroup.hxx:33
tbb::task_arena * CastToTA(void *p)
Definition: TTaskGroup.cxx:43
tbb::task_group * CastToTG(void *p)
Definition: TTaskGroup.cxx:39
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:151
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition: TROOT.cxx:607
UInt_t GetImplicitMTPoolSize()
Returns the size of the pool used for implicit multi-threading.
Definition: TROOT.cxx:614