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

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

Issue 8416019: Add a sequenced worker pool (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 8 years, 11 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 #pragma once
8
9 #include <string>
10
11 #include "base/callback.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/tracked_objects.h"
15 #include "base/base_export.h"
16
17 namespace base {
18
19 // A worker thread pool that enforces ordering between sets of tasks. It also
20 // allows you to specify what should happen to your tasks on shutdown.
21 //
22 // To enforce ordering, get a unique sequence token from the pool and post all
23 // tasks you want to order with the token. All tasks with the same token are
24 // guaranteed to execute serially, though not necessarily on the same thread.
25 //
26 // Example:
27 // SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
28 // pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
29 // FROM_HERE, base::Bind(...));
30 // pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
31 // FROM_HERE, base::Bind(...));
32 //
33 // You can make named sequence tokens to make it easier to share a token
34 // across different components.
35 //
36 // You can also post tasks to the pool without ordering using PostWorkerTask.
37 // These will be executed in an unspecified order. The order of execution
38 // between tasks with different sequence tokens is also unspecified.
39 //
40 // This class is designed to be leaked on shutdown to allow the
41 // CONTINUE_ON_SHUTDOWN behavior to be implemented. To enforce the
42 // BLOCK_SHUTDOWN behavior, you must call Shutdown() which will wait until
43 // the necessary tasks have completed.
44 //
45 // Implementation note: This does not use a base::WorkerPool since that does
46 // not enforce shutdown semantics or allow us to specify how many worker
47 // threads to run. For the typical use case of random background work, we don't
48 // necessarily want to be super aggressive about creating threads.
49 class BASE_EXPORT SequencedWorkerPool {
50 public:
51 // Defines what should happen to a task posted to the worker pool on shutdown.
52 enum WorkerShutdown {
53 // Tasks posted with this mode which have not run at shutdown will be
54 // deleted rather than run, and any tasks with this mode running at
55 // shutdown will be ignored (the worker thread will not be joined).
56 //
57 // This option provides a nice way to post stuff you don't want blocking
58 // shutdown. For example, you might be doing a slow DNS lookup and if it's
59 // blocked on the OS, you may not want to stop shutdown, since the result
60 // doesn't really matter at that point.
61 //
62 // However, you need to be very careful what you do in your callback when
63 // you use this option. Since the thread will continue to run until the OS
64 // terminates the process, the app can be in the process of tearing down
65 // when you're running. This means any singletons or global objects you
66 // use may suddenly become invalid out from under you. For this reason,
67 // it's best to use this only for slow but simple operations like the DNS
68 // example.
69 CONTINUE_ON_SHUTDOWN,
70
71 // Tasks posted with this mode that have not started executing at shutdown
72 // will be deleted rather than executed. However, tasks already in progress
73 // will be completed.
74 SKIP_ON_SHUTDOWN,
75
76 // Tasks posted with this mode will block browser shutdown until they're
77 // executed. Since this can have significant performance implications, use
78 // sparingly.
79 //
80 // Generally, this should be used only for user data, for example, a task
81 // writing a preference file.
82 //
83 // If a task is posted during shutdown, it will not get run since the
84 // workers may already be stopped. In this case, the post operation will
85 // fail (return false) and the task will be deleted.
86 BLOCK_SHUTDOWN,
87 };
88
89 // Opaque identifier that defines sequencing of tasks posted to the worker
90 // pool. See NewSequenceToken().
91 class SequenceToken {
92 public:
93 explicit SequenceToken() : id_(0) {}
94 ~SequenceToken() {}
95
96 bool Equals(const SequenceToken& other) const {
97 return id_ == other.id_;
98 }
99
100 private:
101 friend class SequencedWorkerPool;
102
103 SequenceToken(int id) : id_(id) {}
104
105 int id_;
106 };
107
108 // Allows tests to perform certain actions.
109 class TestingObserver {
110 public:
111 virtual ~TestingObserver() {}
112 virtual void WillWaitForShutdown() = 0;
113 };
114
115 // Pass the maximum number of threads (they will be lazily created as needed)
116 // and a prefix for the thread name to ad in debugging.
117 SequencedWorkerPool(size_t max_threads,
118 const std::string& thread_name_prefix);
119 ~SequencedWorkerPool();
120
121 // Returns a unique token that can be used to sequence tasks posted to
122 // PostSequencedWorkerTask(). Valid tokens are alwys nonzero.
123 SequenceToken GetSequenceToken();
124
125 // Returns the sequence token associated with the given name. Calling this
126 // function multiple times with the same string will always produce the
127 // same sequence token. If the name has not been used before, a new token
128 // will be created.
129 SequenceToken GetNamedSequenceToken(const std::string& name);
130
131 // Posts the given task for execution in the worker pool. Tasks posted with
132 // this function will execute in an unspecified order on a background thread.
133 // Returns true if the task was posted. If your tasks have ordering
134 // requirements, see PostSequencedWorkerTask().
135 //
136 // This class will attempt to delete tasks that aren't run
137 // (non-block-shutdown semantics) but can't guarantee that this happens. If
138 // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there
139 // will be no workers available to delete these tasks. And there may be
140 // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN
141 // tasks. Deleting those tasks before the previous one has completed could
142 // cause nondeterministic crashes because the task could be keeping some
143 // objects alive which do work in their destructor, which could voilate the
144 // assumptions of the running task.
145 //
146 // The task will be guaranteed to run to completion before shutdown
147 // (BLOCK_SHUTDOWN semantics).
148 //
149 // Returns true if the task was posted successfully. This may fail during
150 // shutdown regardless of the specified ShutdownBehavior.
151 bool PostWorkerTask(const tracked_objects::Location& from_here,
152 const base::Closure& task);
153
154 // Same as PostWorkerTask but allows specification of the shutdown behavior.
155 bool PostWorkerTaskWithShutdownBehavior(
156 const tracked_objects::Location& from_here,
157 const base::Closure& task,
158 WorkerShutdown shutdown_behavior);
159
160 // Like PostWorkerTask above, but provides sequencing semantics. This means
161 // that tasks posted with the same sequence token (see GetSequenceToken())
162 // are guaranteed to execute in order. This is useful in cases where you're
163 // doing operations that may depend on previous ones, like appending to a
164 // file.
165 //
166 // The task will be guaranteed to run to completion before shutdown
167 // (BLOCK_SHUTDOWN semantics).
168 //
169 // Returns true if the task was posted successfully. This may fail during
170 // shutdown regardless of the specified ShutdownBehavior.
171 bool PostSequencedWorkerTask(SequenceToken sequence_token,
172 const tracked_objects::Location& from_here,
173 const base::Closure& task);
174
175 // Same as PostSequencedWorkerTask but allows specification of the shutdown
176 // behavior.
177 bool PostSequencedWorkerTaskWithShutdownBehavior(
178 SequenceToken sequence_token,
179 const tracked_objects::Location& from_here,
180 const base::Closure& task,
181 WorkerShutdown shutdown_behavior);
182
183 // Implements the worker pool shutdown. This should be called during app
184 // shutdown, and will discard/join with appropriate tasks before returning.
185 // After this call, subsequent calls to post tasks will fail.
186 void Shutdown();
187
188 // Called by tests to set the testing observer. This is NULL by default
189 // and ownership of the pointer is kept with the caller.
190 void SetTestingObserver(TestingObserver* observer);
191
192 private:
193 class Inner;
194 class Worker;
195
196 friend class Inner;
197 friend class Worker;
198
199 scoped_refptr<Inner> inner_;
200
201 DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
202 };
203
204 } // namespace base
205
206 #endif // BASE_THREADING_SEQUENCED_WORKER_POOL_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698