| OLD | NEW |
| (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_ | |
| OLD | NEW |