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