1 | /* |
2 | Copyright (c) 2005-2019 Intel Corporation |
3 | |
4 | Licensed under the Apache License, Version 2.0 (the "License"); |
5 | you may not use this file except in compliance with the License. |
6 | You may obtain a copy of the License at |
7 | |
8 | http://www.apache.org/licenses/LICENSE-2.0 |
9 | |
10 | Unless required by applicable law or agreed to in writing, software |
11 | distributed under the License is distributed on an "AS IS" BASIS, |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | See the License for the specific language governing permissions and |
14 | limitations under the License. |
15 | */ |
16 | |
17 | #ifndef __TBB_task_scheduler_init_H |
18 | #define __TBB_task_scheduler_init_H |
19 | |
20 | #include "tbb_stddef.h" |
21 | #include "limits.h" |
22 | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE |
23 | #include <new> // nothrow_t |
24 | #endif |
25 | |
26 | namespace tbb { |
27 | |
28 | typedef std::size_t stack_size_type; |
29 | |
30 | //! @cond INTERNAL |
31 | namespace internal { |
32 | //! Internal to library. Should not be used by clients. |
33 | /** @ingroup task_scheduling */ |
34 | class scheduler; |
35 | } // namespace internal |
36 | //! @endcond |
37 | |
38 | //! Class delimiting the scope of task scheduler activity. |
39 | /** A thread can construct a task_scheduler_init object and keep it alive |
40 | while it uses TBB's tasking subsystem (including parallel algorithms). |
41 | |
42 | This class allows to customize properties of the TBB task pool to some extent. |
43 | For example it can limit concurrency level of parallel work initiated by the |
44 | given thread. It also can be used to specify stack size of the TBB worker threads, |
45 | though this setting is not effective if the thread pool has already been created. |
46 | |
47 | If a parallel construct is used without task_scheduler_init object previously |
48 | created, the scheduler will be initialized automatically with default settings, |
49 | and will persist until this thread exits. Default concurrency level is defined |
50 | as described in task_scheduler_init::initialize(). |
51 | @ingroup task_scheduling */ |
52 | class task_scheduler_init: internal::no_copy { |
53 | enum ExceptionPropagationMode { |
54 | propagation_mode_exact = 1u, |
55 | propagation_mode_captured = 2u, |
56 | propagation_mode_mask = propagation_mode_exact | propagation_mode_captured |
57 | }; |
58 | |
59 | /** NULL if not currently initialized. */ |
60 | internal::scheduler* my_scheduler; |
61 | |
62 | bool internal_terminate( bool blocking ); |
63 | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE |
64 | bool __TBB_EXPORTED_METHOD internal_blocking_terminate( bool throwing ); |
65 | #endif |
66 | public: |
67 | |
68 | //! Typedef for number of threads that is automatic. |
69 | static const int automatic = -1; |
70 | |
71 | //! Argument to initialize() or constructor that causes initialization to be deferred. |
72 | static const int deferred = -2; |
73 | |
74 | //! Ensure that scheduler exists for this thread |
75 | /** A value of -1 lets TBB decide on the number of threads, which is usually |
76 | maximal hardware concurrency for this process, that is the number of logical |
77 | CPUs on the machine (possibly limited by the processor affinity mask of this |
78 | process (Windows) or of this thread (Linux, FreeBSD). It is preferable option |
79 | for production code because it helps to avoid nasty surprises when several |
80 | TBB based components run side-by-side or in a nested fashion inside the same |
81 | process. |
82 | |
83 | The number_of_threads is ignored if any other task_scheduler_inits |
84 | currently exist. A thread may construct multiple task_scheduler_inits. |
85 | Doing so does no harm because the underlying scheduler is reference counted. */ |
86 | void __TBB_EXPORTED_METHOD initialize( int number_of_threads=automatic ); |
87 | |
88 | //! The overloaded method with stack size parameter |
89 | /** Overloading is necessary to preserve ABI compatibility */ |
90 | void __TBB_EXPORTED_METHOD initialize( int number_of_threads, stack_size_type thread_stack_size ); |
91 | |
92 | //! Inverse of method initialize. |
93 | void __TBB_EXPORTED_METHOD terminate(); |
94 | |
95 | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE |
96 | #if TBB_USE_EXCEPTIONS |
97 | //! terminate() that waits for worker threads termination. Throws exception on error. |
98 | void blocking_terminate() { |
99 | internal_blocking_terminate( /*throwing=*/true ); |
100 | } |
101 | #endif |
102 | //! terminate() that waits for worker threads termination. Returns false on error. |
103 | bool blocking_terminate(const std::nothrow_t&) __TBB_NOEXCEPT(true) { |
104 | return internal_blocking_terminate( /*throwing=*/false ); |
105 | } |
106 | #endif // __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE |
107 | |
108 | //! Shorthand for default constructor followed by call to initialize(number_of_threads). |
109 | task_scheduler_init( int number_of_threads=automatic, stack_size_type thread_stack_size=0 ) : my_scheduler(NULL) |
110 | { |
111 | // Two lowest order bits of the stack size argument may be taken to communicate |
112 | // default exception propagation mode of the client to be used when the |
113 | // client manually creates tasks in the master thread and does not use |
114 | // explicit task group context object. This is necessary because newer |
115 | // TBB binaries with exact propagation enabled by default may be used |
116 | // by older clients that expect tbb::captured_exception wrapper. |
117 | // All zeros mean old client - no preference. |
118 | __TBB_ASSERT( !(thread_stack_size & propagation_mode_mask), "Requested stack size is not aligned" ); |
119 | #if TBB_USE_EXCEPTIONS |
120 | thread_stack_size |= TBB_USE_CAPTURED_EXCEPTION ? propagation_mode_captured : propagation_mode_exact; |
121 | #endif /* TBB_USE_EXCEPTIONS */ |
122 | initialize( number_of_threads, thread_stack_size ); |
123 | } |
124 | |
125 | //! Destroy scheduler for this thread if thread has no other live task_scheduler_inits. |
126 | ~task_scheduler_init() { |
127 | if( my_scheduler ) |
128 | terminate(); |
129 | internal::poison_pointer( my_scheduler ); |
130 | } |
131 | //! Returns the number of threads TBB scheduler would create if initialized by default. |
132 | /** Result returned by this method does not depend on whether the scheduler |
133 | has already been initialized. |
134 | |
135 | Because tbb 2.0 does not support blocking tasks yet, you may use this method |
136 | to boost the number of threads in the tbb's internal pool, if your tasks are |
137 | doing I/O operations. The optimal number of additional threads depends on how |
138 | much time your tasks spend in the blocked state. |
139 | |
140 | Before TBB 3.0 U4 this method returned the number of logical CPU in the |
141 | system. Currently on Windows, Linux and FreeBSD it returns the number of |
142 | logical CPUs available to the current process in accordance with its affinity |
143 | mask. |
144 | |
145 | NOTE: The return value of this method never changes after its first invocation. |
146 | This means that changes in the process affinity mask that took place after |
147 | this method was first invoked will not affect the number of worker threads |
148 | in the TBB worker threads pool. */ |
149 | static int __TBB_EXPORTED_FUNC default_num_threads (); |
150 | |
151 | //! Returns true if scheduler is active (initialized); false otherwise |
152 | bool is_active() const { return my_scheduler != NULL; } |
153 | }; |
154 | |
155 | } // namespace tbb |
156 | |
157 | #endif /* __TBB_task_scheduler_init_H */ |
158 | |