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 |