Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Side by Side Diff: base/threading/sequenced_worker_pool.h

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/threading/post_task_and_reply_impl.cc ('k') | base/threading/sequenced_worker_pool.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_
6 #define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
7
8 #include <cstddef>
9 #include <string>
10
11 #include "base/base_export.h"
12 #include "base/basictypes.h"
13 #include "base/callback_forward.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/task_runner.h"
18
19 namespace tracked_objects {
20 class Location;
21 } // namespace tracked_objects
22
23 namespace base {
24
25 class SingleThreadTaskRunner;
26
27 template <class T> class DeleteHelper;
28
29 class SequencedTaskRunner;
30
31 // A worker thread pool that enforces ordering between sets of tasks. It also
32 // allows you to specify what should happen to your tasks on shutdown.
33 //
34 // To enforce ordering, get a unique sequence token from the pool and post all
35 // tasks you want to order with the token. All tasks with the same token are
36 // guaranteed to execute serially, though not necessarily on the same thread.
37 // This means that:
38 //
39 // - No two tasks with the same token will run at the same time.
40 //
41 // - Given two tasks T1 and T2 with the same token such that T2 will
42 // run after T1, then T2 will start after T1 is destroyed.
43 //
44 // - If T2 will run after T1, then all memory changes in T1 and T1's
45 // destruction will be visible to T2.
46 //
47 // Example:
48 // SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
49 // pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
50 // FROM_HERE, base::Bind(...));
51 // pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
52 // FROM_HERE, base::Bind(...));
53 //
54 // You can make named sequence tokens to make it easier to share a token
55 // across different components.
56 //
57 // You can also post tasks to the pool without ordering using PostWorkerTask.
58 // These will be executed in an unspecified order. The order of execution
59 // between tasks with different sequence tokens is also unspecified.
60 //
61 // This class may be leaked on shutdown to facilitate fast shutdown. The
62 // expected usage, however, is to call Shutdown(), which correctly accounts
63 // for CONTINUE_ON_SHUTDOWN behavior and is required for BLOCK_SHUTDOWN
64 // behavior.
65 //
66 // Implementation note: This does not use a base::WorkerPool since that does
67 // not enforce shutdown semantics or allow us to specify how many worker
68 // threads to run. For the typical use case of random background work, we don't
69 // necessarily want to be super aggressive about creating threads.
70 //
71 // Note that SequencedWorkerPool is RefCountedThreadSafe (inherited
72 // from TaskRunner).
73 //
74 // Test-only code should wrap this in a base::SequencedWorkerPoolOwner to avoid
75 // memory leaks. See http://crbug.com/273800
76 class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
77 public:
78 // Defines what should happen to a task posted to the worker pool on
79 // shutdown.
80 enum WorkerShutdown {
81 // Tasks posted with this mode which have not run at shutdown will be
82 // deleted rather than run, and any tasks with this mode running at
83 // shutdown will be ignored (the worker thread will not be joined).
84 //
85 // This option provides a nice way to post stuff you don't want blocking
86 // shutdown. For example, you might be doing a slow DNS lookup and if it's
87 // blocked on the OS, you may not want to stop shutdown, since the result
88 // doesn't really matter at that point.
89 //
90 // However, you need to be very careful what you do in your callback when
91 // you use this option. Since the thread will continue to run until the OS
92 // terminates the process, the app can be in the process of tearing down
93 // when you're running. This means any singletons or global objects you
94 // use may suddenly become invalid out from under you. For this reason,
95 // it's best to use this only for slow but simple operations like the DNS
96 // example.
97 CONTINUE_ON_SHUTDOWN,
98
99 // Tasks posted with this mode that have not started executing at
100 // shutdown will be deleted rather than executed. However, any tasks that
101 // have already begun executing when shutdown is called will be allowed
102 // to continue, and will block shutdown until completion.
103 //
104 // Note: Because Shutdown() may block while these tasks are executing,
105 // care must be taken to ensure that they do not block on the thread that
106 // called Shutdown(), as this may lead to deadlock.
107 SKIP_ON_SHUTDOWN,
108
109 // Tasks posted with this mode will block shutdown until they're
110 // executed. Since this can have significant performance implications,
111 // use sparingly.
112 //
113 // Generally, this should be used only for user data, for example, a task
114 // writing a preference file.
115 //
116 // If a task is posted during shutdown, it will not get run since the
117 // workers may already be stopped. In this case, the post operation will
118 // fail (return false) and the task will be deleted.
119 BLOCK_SHUTDOWN,
120 };
121
122 // Opaque identifier that defines sequencing of tasks posted to the worker
123 // pool.
124 class SequenceToken {
125 public:
126 SequenceToken() : id_(0) {}
127 ~SequenceToken() {}
128
129 bool Equals(const SequenceToken& other) const {
130 return id_ == other.id_;
131 }
132
133 // Returns false if current thread is executing an unsequenced task.
134 bool IsValid() const {
135 return id_ != 0;
136 }
137
138 private:
139 friend class SequencedWorkerPool;
140
141 explicit SequenceToken(int id) : id_(id) {}
142
143 int id_;
144 };
145
146 // Allows tests to perform certain actions.
147 class TestingObserver {
148 public:
149 virtual ~TestingObserver() {}
150 virtual void OnHasWork() = 0;
151 virtual void WillWaitForShutdown() = 0;
152 virtual void OnDestruct() = 0;
153 };
154
155 // Gets the SequencedToken of the current thread.
156 // If current thread is not a SequencedWorkerPool worker thread or is running
157 // an unsequenced task, returns an invalid SequenceToken.
158 static SequenceToken GetSequenceTokenForCurrentThread();
159
160 // When constructing a SequencedWorkerPool, there must be a
161 // MessageLoop on the current thread unless you plan to deliberately
162 // leak it.
163
164 // Pass the maximum number of threads (they will be lazily created as needed)
165 // and a prefix for the thread name to aid in debugging.
166 SequencedWorkerPool(size_t max_threads,
167 const std::string& thread_name_prefix);
168
169 // Like above, but with |observer| for testing. Does not take
170 // ownership of |observer|.
171 SequencedWorkerPool(size_t max_threads,
172 const std::string& thread_name_prefix,
173 TestingObserver* observer);
174
175 // Returns a unique token that can be used to sequence tasks posted to
176 // PostSequencedWorkerTask(). Valid tokens are always nonzero.
177 SequenceToken GetSequenceToken();
178
179 // Returns the sequence token associated with the given name. Calling this
180 // function multiple times with the same string will always produce the
181 // same sequence token. If the name has not been used before, a new token
182 // will be created.
183 SequenceToken GetNamedSequenceToken(const std::string& name);
184
185 // Returns a SequencedTaskRunner wrapper which posts to this
186 // SequencedWorkerPool using the given sequence token. Tasks with nonzero
187 // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
188 // are posted with BLOCK_SHUTDOWN behavior.
189 scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner(
190 SequenceToken token);
191
192 // Returns a SequencedTaskRunner wrapper which posts to this
193 // SequencedWorkerPool using the given sequence token. Tasks with nonzero
194 // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
195 // are posted with the given shutdown behavior.
196 scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior(
197 SequenceToken token,
198 WorkerShutdown shutdown_behavior);
199
200 // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using
201 // the given shutdown behavior. Tasks with nonzero delay are posted with
202 // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the
203 // given shutdown behavior.
204 scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior(
205 WorkerShutdown shutdown_behavior);
206
207 // Posts the given task for execution in the worker pool. Tasks posted with
208 // this function will execute in an unspecified order on a background thread.
209 // Returns true if the task was posted. If your tasks have ordering
210 // requirements, see PostSequencedWorkerTask().
211 //
212 // This class will attempt to delete tasks that aren't run
213 // (non-block-shutdown semantics) but can't guarantee that this happens. If
214 // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there
215 // will be no workers available to delete these tasks. And there may be
216 // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN
217 // tasks. Deleting those tasks before the previous one has completed could
218 // cause nondeterministic crashes because the task could be keeping some
219 // objects alive which do work in their destructor, which could voilate the
220 // assumptions of the running task.
221 //
222 // The task will be guaranteed to run to completion before shutdown
223 // (BLOCK_SHUTDOWN semantics).
224 //
225 // Returns true if the task was posted successfully. This may fail during
226 // shutdown regardless of the specified ShutdownBehavior.
227 bool PostWorkerTask(const tracked_objects::Location& from_here,
228 const Closure& task);
229
230 // Same as PostWorkerTask but allows a delay to be specified (although doing
231 // so changes the shutdown behavior). The task will be run after the given
232 // delay has elapsed.
233 //
234 // If the delay is nonzero, the task won't be guaranteed to run to completion
235 // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
236 // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the
237 // task will be guaranteed to run to completion before shutdown
238 // (BLOCK_SHUTDOWN semantics).
239 bool PostDelayedWorkerTask(const tracked_objects::Location& from_here,
240 const Closure& task,
241 TimeDelta delay);
242
243 // Same as PostWorkerTask but allows specification of the shutdown behavior.
244 bool PostWorkerTaskWithShutdownBehavior(
245 const tracked_objects::Location& from_here,
246 const Closure& task,
247 WorkerShutdown shutdown_behavior);
248
249 // Like PostWorkerTask above, but provides sequencing semantics. This means
250 // that tasks posted with the same sequence token (see GetSequenceToken())
251 // are guaranteed to execute in order. This is useful in cases where you're
252 // doing operations that may depend on previous ones, like appending to a
253 // file.
254 //
255 // The task will be guaranteed to run to completion before shutdown
256 // (BLOCK_SHUTDOWN semantics).
257 //
258 // Returns true if the task was posted successfully. This may fail during
259 // shutdown regardless of the specified ShutdownBehavior.
260 bool PostSequencedWorkerTask(SequenceToken sequence_token,
261 const tracked_objects::Location& from_here,
262 const Closure& task);
263
264 // Like PostSequencedWorkerTask above, but allows you to specify a named
265 // token, which saves an extra call to GetNamedSequenceToken.
266 bool PostNamedSequencedWorkerTask(const std::string& token_name,
267 const tracked_objects::Location& from_here,
268 const Closure& task);
269
270 // Same as PostSequencedWorkerTask but allows a delay to be specified
271 // (although doing so changes the shutdown behavior). The task will be run
272 // after the given delay has elapsed.
273 //
274 // If the delay is nonzero, the task won't be guaranteed to run to completion
275 // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
276 // If the delay is zero, this behaves exactly like PostSequencedWorkerTask,
277 // i.e. the task will be guaranteed to run to completion before shutdown
278 // (BLOCK_SHUTDOWN semantics).
279 bool PostDelayedSequencedWorkerTask(
280 SequenceToken sequence_token,
281 const tracked_objects::Location& from_here,
282 const Closure& task,
283 TimeDelta delay);
284
285 // Same as PostSequencedWorkerTask but allows specification of the shutdown
286 // behavior.
287 bool PostSequencedWorkerTaskWithShutdownBehavior(
288 SequenceToken sequence_token,
289 const tracked_objects::Location& from_here,
290 const Closure& task,
291 WorkerShutdown shutdown_behavior);
292
293 // TaskRunner implementation. Forwards to PostDelayedWorkerTask().
294 bool PostDelayedTask(const tracked_objects::Location& from_here,
295 const Closure& task,
296 TimeDelta delay) override;
297 bool RunsTasksOnCurrentThread() const override;
298
299 // Returns true if the current thread is processing a task with the given
300 // sequence_token.
301 bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
302
303 // Blocks until all pending tasks are complete. This should only be called in
304 // unit tests when you want to validate something that should have happened.
305 // This will not flush delayed tasks; delayed tasks get deleted.
306 //
307 // Note that calling this will not prevent other threads from posting work to
308 // the queue while the calling thread is waiting on Flush(). In this case,
309 // Flush will return only when there's no more work in the queue. Normally,
310 // this doesn't come up since in a test, all the work is being posted from
311 // the main thread.
312 void FlushForTesting();
313
314 // Spuriously signal that there is work to be done.
315 void SignalHasWorkForTesting();
316
317 // Implements the worker pool shutdown. This should be called during app
318 // shutdown, and will discard/join with appropriate tasks before returning.
319 // After this call, subsequent calls to post tasks will fail.
320 //
321 // Must be called from the same thread this object was constructed on.
322 void Shutdown() { Shutdown(0); }
323
324 // A variant that allows an arbitrary number of new blocking tasks to be
325 // posted during shutdown. The tasks cannot be posted within the execution
326 // context of tasks whose shutdown behavior is not BLOCKING_SHUTDOWN. Once
327 // the limit is reached, subsequent calls to post task fail in all cases.
328 // Must be called from the same thread this object was constructed on.
329 void Shutdown(int max_new_blocking_tasks_after_shutdown);
330
331 // Check if Shutdown was called for given threading pool. This method is used
332 // for aborting time consuming operation to avoid blocking shutdown.
333 //
334 // Can be called from any thread.
335 bool IsShutdownInProgress();
336
337 protected:
338 ~SequencedWorkerPool() override;
339
340 void OnDestruct() const override;
341
342 private:
343 friend class RefCountedThreadSafe<SequencedWorkerPool>;
344 friend class DeleteHelper<SequencedWorkerPool>;
345
346 class Inner;
347 class Worker;
348
349 const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_;
350
351 // Avoid pulling in too many headers by putting (almost) everything
352 // into |inner_|.
353 const scoped_ptr<Inner> inner_;
354
355 DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
356 };
357
358 } // namespace base
359
360 #endif // BASE_THREADING_SEQUENCED_WORKER_POOL_H_
OLDNEW
« no previous file with comments | « base/threading/post_task_and_reply_impl.cc ('k') | base/threading/sequenced_worker_pool.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698