blob: 41847b7c9c367692af9d6e195499b2c762519360 [file] [log] [blame] [view]
fdoraybacba4a22017-05-10 21:10:001# Threading and Tasks in Chrome
2
3[TOC]
4
Gabriel Charette8917f4c2018-11-22 15:50:285Note: See [Threading and Tasks FAQ](threading_and_tasks_faq.md) for more
6examples.
7
fdoraybacba4a22017-05-10 21:10:008## Overview
9
Gabriel Charette90480312018-02-16 15:10:0510Chromium is a very multithreaded product. We try to keep the UI as responsive as
11possible, and this means not blocking the UI thread with any blocking I/O or
12other expensive operations. Our approach is to use message passing as the way of
13communicating between threads. We discourage locking and threadsafe
14objects. Instead, objects live on only one thread, we pass messages between
15threads for communication, and we use callback interfaces (implemented by
16message passing) for most cross-thread requests.
17
Gabriel Charette364a16a2019-02-06 21:12:1518### Nomenclature
Gabriel Charetteb984d672019-02-12 21:53:2719 * **Thread-unsafe**: The vast majority of types in Chromium are thread-unsafe
20 by design. Access to such types/methods must be synchronized, typically by
21 sequencing access through a single `base::SequencedTaskRunner` (this should
22 be enforced by a `SEQUENCE_CHECKER`) or via low-level synchronization (e.g.
23 locks -- but [prefer sequences](#Using-Sequences-Instead-of-Locks)).
Gabriel Charette364a16a2019-02-06 21:12:1524 * **Thread-affine**: Such types/methods need to be always accessed from the
Gabriel Charetteb984d672019-02-12 21:53:2725 same physical thread (i.e. from the same `base::SingleThreadTaskRunner`) and
26 should use `THREAD_CHECKER` to verify that they are. Short of using a
27 third-party API or having a leaf dependency which is thread-affine: there's
28 pretty much no reason for a type to be thread-affine in Chromium. Note that
29 `base::SingleThreadTaskRunner` is-a `base::SequencedTaskRunner` so
30 thread-affine is a subset of thread-unsafe. Thread-affine is also sometimes
31 referred to as **thread-hostile**.
Gabriel Charette364a16a2019-02-06 21:12:1532 * **Thread-safe**: Such types/methods can be safely accessed concurrently.
Gabriel Charetteb984d672019-02-12 21:53:2733 * **Thread-compatible**: Such types provide safe concurrent access to const
34 methods but require synchronization for non-const (or mixed const/non-const
35 access). Chromium doesn't expose reader-writer locks; as such, the only use
36 case for this is objects (typically globals) which are initialized once in a
Gabriel Charette364a16a2019-02-06 21:12:1537 thread-safe manner (either in the single-threaded phase of startup or lazily
38 through a thread-safe static-local-initialization paradigm a la
Gabriel Charetteb984d672019-02-12 21:53:2739 `base::NoDestructor`) and forever after immutable.
40 * **Immutable**: A subset of thread-compatible types which cannot be modified
41 after construction.
Gabriel Charette364a16a2019-02-06 21:12:1542 * **Sequence-friendly**: Such types/methods are thread-unsafe types which
43 support being invoked from a `base::SequencedTaskRunner`. Ideally this would
44 be the case for all thread-unsafe types but legacy code sometimes has
45 overzealous checks that enforce thread-affinity in mere thread-unsafe
46 scenarios. See [Prefer Sequences to Threads](#prefer-sequences-to-threads)
47 below for more details.
48
fdoraybacba4a22017-05-10 21:10:0049### Threads
50
51Every Chrome process has
52
53* a main thread
54 * in the browser process: updates the UI
55 * in renderer processes: runs most of Blink
56* an IO thread
57 * in the browser process: handles IPCs and network requests
58 * in renderer processes: handles IPCs
59* a few more special-purpose threads
60* and a pool of general-purpose threads
61
62Most threads have a loop that gets tasks from a queue and runs them (the queue
63may be shared between multiple threads).
64
65### Tasks
66
67A task is a `base::OnceClosure` added to a queue for asynchronous execution.
68
69A `base::OnceClosure` stores a function pointer and arguments. It has a `Run()`
70method that invokes the function pointer using the bound arguments. It is
71created using `base::BindOnce`. (ref. [Callback<> and Bind()
72documentation](callback.md)).
73
74```
75void TaskA() {}
76void TaskB(int v) {}
77
78auto task_a = base::BindOnce(&TaskA);
79auto task_b = base::BindOnce(&TaskB, 42);
80```
81
82A group of tasks can be executed in one of the following ways:
83
84* [Parallel](#Posting-a-Parallel-Task): No task execution ordering, possibly all
85 at once on any thread
86* [Sequenced](#Posting-a-Sequenced-Task): Tasks executed in posting order, one
87 at a time on any thread.
88* [Single Threaded](#Posting-Multiple-Tasks-to-the-Same-Thread): Tasks executed
89 in posting order, one at a time on a single thread.
90 * [COM Single Threaded](#Posting-Tasks-to-a-COM-Single-Thread-Apartment-STA_Thread-Windows_):
91 A variant of single threaded with COM initialized.
92
gab2a4576052017-06-07 23:36:1293### Prefer Sequences to Threads
94
Gabriel Charetteb86e5fe62017-06-08 19:39:2895**Sequenced execution mode is far preferred to Single Threaded** in scenarios
gab2a4576052017-06-07 23:36:1296that require mere thread-safety as it opens up scheduling paradigms that
97wouldn't be possible otherwise (sequences can hop threads instead of being stuck
98behind unrelated work on a dedicated thread). Ability to hop threads also means
99the thread count can dynamically adapt to the machine's true resource
Gabriel Charette90480312018-02-16 15:10:05100availability (increased parallelism on bigger machines, avoids trashing
101resources on smaller machines).
gab2a4576052017-06-07 23:36:12102
103Many core APIs were recently made sequence-friendly (classes are rarely
Gabriel Charette364a16a2019-02-06 21:12:15104thread-affine -- i.e. only when using third-party APIs that are thread-affine;
105even ThreadLocalStorage has a SequenceLocalStorage equivalent). But the codebase
106has long evolved assuming single-threaded contexts... If your class could run on
107a sequence but is blocked by an overzealous use of
gab2a4576052017-06-07 23:36:12108ThreadChecker/ThreadTaskRunnerHandle/SingleThreadTaskRunner in a leaf
109dependency, consider fixing that dependency for everyone's benefit (or at the
110very least file a blocking bug against https://crbug.com/675631 and flag your
111use of base::CreateSingleThreadTaskRunnerWithTraits() with a TODO against your
112bug to use base::CreateSequencedTaskRunnerWithTraits() when fixed).
113
Gabriel Charette01567ac2017-06-09 15:31:10114Detailed documentation on how to migrate from single-threaded contexts to
Gabriel Charette8917f4c2018-11-22 15:50:28115sequenced contexts can be found [here](threading_and_tasks_faq.md#How-to-migrate-from-SingleThreadTaskRunner-to-SequencedTaskRunner).
Gabriel Charette01567ac2017-06-09 15:31:10116
gab2a4576052017-06-07 23:36:12117The discussion below covers all of these ways to execute tasks in details.
fdoraybacba4a22017-05-10 21:10:00118
119## Posting a Parallel Task
120
Gabriel Charette52fa3ae2019-04-15 21:44:37121### Direct Posting to the Thread Pool
fdoraybacba4a22017-05-10 21:10:00122
123A task that can run on any thread and doesn’t have ordering or mutual exclusion
124requirements with other tasks should be posted using one of the
125`base::PostTask*()` functions defined in
Gabriel Charette04b138f2018-08-06 00:03:22126[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h).
fdoraybacba4a22017-05-10 21:10:00127
128```cpp
129base::PostTask(FROM_HERE, base::BindOnce(&Task));
130```
131
132This posts tasks with default traits.
133
134The `base::PostTask*WithTraits()` functions allow the caller to provide
135additional details about the task via TaskTraits (ref.
136[Annotating Tasks with TaskTraits](#Annotating-Tasks-with-TaskTraits)).
137
138```cpp
139base::PostTaskWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00140 FROM_HERE, {base::TaskPriority::BEST_EFFORT, MayBlock()},
fdoraybacba4a22017-05-10 21:10:00141 base::BindOnce(&Task));
142```
143
fdoray52bf5552017-05-11 12:43:59144### Posting via a TaskRunner
fdoraybacba4a22017-05-10 21:10:00145
146A parallel
147[`TaskRunner`](https://cs.chromium.org/chromium/src/base/task_runner.h) is an
148alternative to calling `base::PostTask*()` directly. This is mainly useful when
149it isn’t known in advance whether tasks will be posted in parallel, in sequence,
fdoray52bf5552017-05-11 12:43:59150or to a single-thread (ref.
151[Posting a Sequenced Task](#Posting-a-Sequenced-Task),
152[Posting Multiple Tasks to the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread)).
153Since `TaskRunner` is the base class of `SequencedTaskRunner` and
154`SingleThreadTaskRunner`, a `scoped_refptr<TaskRunner>` member can hold a
fdoraybacba4a22017-05-10 21:10:00155`TaskRunner`, a `SequencedTaskRunner` or a `SingleThreadTaskRunner`.
156
157```cpp
158class A {
159 public:
160 A() = default;
161
162 void set_task_runner_for_testing(
163 scoped_refptr<base::TaskRunner> task_runner) {
164 task_runner_ = std::move(task_runner);
165 }
166
167 void DoSomething() {
168 // In production, A is always posted in parallel. In test, it is posted to
169 // the TaskRunner provided via set_task_runner_for_testing().
170 task_runner_->PostTask(FROM_HERE, base::BindOnce(&A));
171 }
172
173 private:
174 scoped_refptr<base::TaskRunner> task_runner_ =
175 base::CreateTaskRunnerWithTraits({base::TaskPriority::USER_VISIBLE});
176};
177```
178
179Unless a test needs to control precisely how tasks are executed, it is preferred
180to call `base::PostTask*()` directly (ref. [Testing](#Testing) for less invasive
181ways of controlling tasks in tests).
182
183## Posting a Sequenced Task
184
185A sequence is a set of tasks that run one at a time in posting order (not
186necessarily on the same thread). To post tasks as part of a sequence, use a
Gabriel Charette90480312018-02-16 15:10:05187[`SequencedTaskRunner`](https://cs.chromium.org/chromium/src/base/sequenced_task_runner.h).
fdoraybacba4a22017-05-10 21:10:00188
189### Posting to a New Sequence
190
191A `SequencedTaskRunner` can be created by
192`base::CreateSequencedTaskRunnerWithTraits()`.
193
194```cpp
195scoped_refptr<SequencedTaskRunner> sequenced_task_runner =
196 base::CreateSequencedTaskRunnerWithTraits(...);
197
198// TaskB runs after TaskA completes.
199sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA));
200sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB));
201```
202
203### Posting to the Current Sequence
204
205The `SequencedTaskRunner` to which the current task was posted can be obtained
206via
207[`SequencedTaskRunnerHandle::Get()`](https://cs.chromium.org/chromium/src/base/threading/sequenced_task_runner_handle.h).
208
209*** note
210**NOTE:** it is invalid to call `SequencedTaskRunnerHandle::Get()` from a
211parallel task, but it is valid from a single-threaded task (a
212`SingleThreadTaskRunner` is a `SequencedTaskRunner`).
213***
214
215```cpp
216// The task will run after any task that has already been posted
217// to the SequencedTaskRunner to which the current task was posted
218// (in particular, it will run after the current task completes).
219// It is also guaranteed that it won’t run concurrently with any
220// task posted to that SequencedTaskRunner.
221base::SequencedTaskRunnerHandle::Get()->
222 PostTask(FROM_HERE, base::BindOnce(&Task));
223```
224
225## Using Sequences Instead of Locks
226
227Usage of locks is discouraged in Chrome. Sequences inherently provide
Gabriel Charettea3ccc972018-11-13 14:43:12228thread-safety. Prefer classes that are always accessed from the same
229sequence to managing your own thread-safety with locks.
230
231**Thread-safe but not thread-affine; how so?** Tasks posted to the same sequence
232will run in sequential order. After a sequenced task completes, the next task
233may be picked up by a different worker thread, but that task is guaranteed to
234see any side-effects caused by the previous one(s) on its sequence.
fdoraybacba4a22017-05-10 21:10:00235
236```cpp
237class A {
238 public:
239 A() {
240 // Do not require accesses to be on the creation sequence.
isherman8c33b8a2017-06-27 19:18:30241 DETACH_FROM_SEQUENCE(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00242 }
243
244 void AddValue(int v) {
245 // Check that all accesses are on the same sequence.
isherman8c33b8a2017-06-27 19:18:30246 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00247 values_.push_back(v);
248}
249
250 private:
isherman8c33b8a2017-06-27 19:18:30251 SEQUENCE_CHECKER(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00252
253 // No lock required, because all accesses are on the
254 // same sequence.
255 std::vector<int> values_;
256};
257
258A a;
259scoped_refptr<SequencedTaskRunner> task_runner_for_a = ...;
Mike Bjorged3a09842018-05-15 18:37:28260task_runner_for_a->PostTask(FROM_HERE,
261 base::BindOnce(&A::AddValue, base::Unretained(&a), 42));
262task_runner_for_a->PostTask(FROM_HERE,
263 base::BindOnce(&A::AddValue, base::Unretained(&a), 27));
fdoraybacba4a22017-05-10 21:10:00264
265// Access from a different sequence causes a DCHECK failure.
266scoped_refptr<SequencedTaskRunner> other_task_runner = ...;
267other_task_runner->PostTask(FROM_HERE,
Mike Bjorged3a09842018-05-15 18:37:28268 base::BindOnce(&A::AddValue, base::Unretained(&a), 1));
fdoraybacba4a22017-05-10 21:10:00269```
270
Gabriel Charette90480312018-02-16 15:10:05271Locks should only be used to swap in a shared data structure that can be
272accessed on multiple threads. If one thread updates it based on expensive
273computation or through disk access, then that slow work should be done without
274holding on to the lock. Only when the result is available should the lock be
275used to swap in the new data. An example of this is in PluginList::LoadPlugins
Haiyang Pana2328022019-04-03 12:07:26276([`content/browser/plugin_list.cc`](https://cs.chromium.org/chromium/src/content/browser/plugin_list.cc)). If you must use locks,
Gabriel Charette90480312018-02-16 15:10:05277[here](https://www.chromium.org/developers/lock-and-condition-variable) are some
278best practices and pitfalls to avoid.
279
280In order to write non-blocking code, many APIs in Chromium are asynchronous.
281Usually this means that they either need to be executed on a particular
282thread/sequence and will return results via a custom delegate interface, or they
283take a `base::Callback<>` object that is called when the requested operation is
284completed. Executing work on a specific thread/sequence is covered in the
285PostTask sections above.
286
fdoraybacba4a22017-05-10 21:10:00287## Posting Multiple Tasks to the Same Thread
288
289If multiple tasks need to run on the same thread, post them to a
290[`SingleThreadTaskRunner`](https://cs.chromium.org/chromium/src/base/single_thread_task_runner.h).
291All tasks posted to the same `SingleThreadTaskRunner` run on the same thread in
292posting order.
293
294### Posting to the Main Thread or to the IO Thread in the Browser Process
295
Eric Seckler6cf08db82018-08-30 12:01:55296To post tasks to the main thread or to the IO thread, use
297`base::PostTaskWithTraits()` or get the appropriate SingleThreadTaskRunner using
298`base::CreateSingleThreadTaskRunnerWithTraits`, supplying a `BrowserThread::ID`
299as trait. For this, you'll also need to include
300[`content/public/browser/browser_task_traits.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_task_traits.h).
fdoraybacba4a22017-05-10 21:10:00301
302```cpp
Eric Seckler6cf08db82018-08-30 12:01:55303base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, ...);
fdoraybacba4a22017-05-10 21:10:00304
Eric Seckler6cf08db82018-08-30 12:01:55305base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})
fdoraybacba4a22017-05-10 21:10:00306 ->PostTask(FROM_HERE, ...);
307```
308
309The main thread and the IO thread are already super busy. Therefore, prefer
fdoray52bf5552017-05-11 12:43:59310posting to a general purpose thread when possible (ref.
311[Posting a Parallel Task](#Posting-a-Parallel-Task),
312[Posting a Sequenced task](#Posting-a-Sequenced-Task)).
313Good reasons to post to the main thread are to update the UI or access objects
314that are bound to it (e.g. `Profile`). A good reason to post to the IO thread is
315to access the internals of components that are bound to it (e.g. IPCs, network).
316Note: It is not necessary to have an explicit post task to the IO thread to
317send/receive an IPC or send/receive data on the network.
fdoraybacba4a22017-05-10 21:10:00318
319### Posting to the Main Thread in a Renderer Process
320TODO
321
322### Posting to a Custom SingleThreadTaskRunner
323
324If multiple tasks need to run on the same thread and that thread doesn’t have to
325be the main thread or the IO thread, post them to a `SingleThreadTaskRunner`
326created by `base::CreateSingleThreadTaskRunnerWithTraits`.
327
328```cpp
329scoped_refptr<SequencedTaskRunner> single_thread_task_runner =
330 base::CreateSingleThreadTaskRunnerWithTraits(...);
331
332// TaskB runs after TaskA completes. Both tasks run on the same thread.
333single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA));
334single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB));
335```
336
337*** note
338**IMPORTANT:** You should rarely need this, most classes in Chromium require
339thread-safety (which sequences provide) not thread-affinity. If an API you’re
340using is incorrectly thread-affine (i.e. using
341[`base::ThreadChecker`](https://cs.chromium.org/chromium/src/base/threading/thread_checker.h)
342when it’s merely thread-unsafe and should use
343[`base::SequenceChecker`](https://cs.chromium.org/chromium/src/base/sequence_checker.h)),
Gabriel Charette41f4a482019-01-15 00:15:50344please consider
345[`fixing it`](threading_and_tasks_faq.md#How-to-migrate-from-SingleThreadTaskRunner-to-SequencedTaskRunner)
346instead of making things worse by also making your API thread-affine.
fdoraybacba4a22017-05-10 21:10:00347***
348
349### Posting to the Current Thread
350
351*** note
352**IMPORTANT:** To post a task that needs mutual exclusion with the current
353sequence of tasks but doesn’t absolutely need to run on the current thread, use
354`SequencedTaskRunnerHandle::Get()` instead of `ThreadTaskRunnerHandle::Get()`
355(ref. [Posting to the Current Sequence](#Posting-to-the-Current-Sequence)). That
356will better document the requirements of the posted task. In a single-thread
357task, `SequencedTaskRunnerHandle::Get()` is equivalent to
358`ThreadTaskRunnerHandle::Get()`.
359***
360
361To post a task to the current thread, use [`ThreadTaskRunnerHandle`](https://cs.chromium.org/chromium/src/base/threading/thread_task_runner_handle.h).
362
363```cpp
364// The task will run on the current thread in the future.
365base::ThreadTaskRunnerHandle::Get()->PostTask(
366 FROM_HERE, base::BindOnce(&Task));
367```
368
369*** note
370**NOTE:** It is invalid to call `ThreadTaskRunnerHandle::Get()` from a parallel
371or a sequenced task.
372***
373
374## Posting Tasks to a COM Single-Thread Apartment (STA) Thread (Windows)
375
376Tasks that need to run on a COM Single-Thread Apartment (STA) thread must be
377posted to a `SingleThreadTaskRunner` returned by
378`CreateCOMSTATaskRunnerWithTraits()`. As mentioned in [Posting Multiple Tasks to
379the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread), all tasks posted
380to the same `SingleThreadTaskRunner` run on the same thread in posting order.
381
382```cpp
383// Task(A|B|C)UsingCOMSTA will run on the same COM STA thread.
384
385void TaskAUsingCOMSTA() {
386 // [ This runs on a COM STA thread. ]
387
388 // Make COM STA calls.
389 // ...
390
391 // Post another task to the current COM STA thread.
392 base::ThreadTaskRunnerHandle::Get()->PostTask(
393 FROM_HERE, base::BindOnce(&TaskCUsingCOMSTA));
394}
395void TaskBUsingCOMSTA() { }
396void TaskCUsingCOMSTA() { }
397
398auto com_sta_task_runner = base::CreateCOMSTATaskRunnerWithTraits(...);
399com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskAUsingCOMSTA));
400com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskBUsingCOMSTA));
401```
402
403## Annotating Tasks with TaskTraits
404
Gabriel Charette04b138f2018-08-06 00:03:22405[`TaskTraits`](https://cs.chromium.org/chromium/src/base/task/task_traits.h)
Gabriel Charette52fa3ae2019-04-15 21:44:37406encapsulate information about a task that helps the thread pool make better
fdoraybacba4a22017-05-10 21:10:00407scheduling decisions.
408
409All `PostTask*()` functions in
Gabriel Charette04b138f2018-08-06 00:03:22410[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h)
fdoraybacba4a22017-05-10 21:10:00411have an overload that takes `TaskTraits` as argument and one that doesn’t. The
412overload that doesn’t take `TaskTraits` as argument is appropriate for tasks
413that:
414- Don’t block (ref. MayBlock and WithBaseSyncPrimitives).
415- Prefer inheriting the current priority to specifying their own.
Gabriel Charette52fa3ae2019-04-15 21:44:37416- Can either block shutdown or be skipped on shutdown (thread pool is free to
417 choose a fitting default).
fdoraybacba4a22017-05-10 21:10:00418Tasks that don’t match this description must be posted with explicit TaskTraits.
419
Gabriel Charette04b138f2018-08-06 00:03:22420[`base/task/task_traits.h`](https://cs.chromium.org/chromium/src/base/task/task_traits.h)
Eric Seckler6cf08db82018-08-30 12:01:55421provides exhaustive documentation of available traits. The content layer also
422provides additional traits in
423[`content/public/browser/browser_task_traits.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_task_traits.h)
424to facilitate posting a task onto a BrowserThread.
425
426Below are some examples of how to specify `TaskTraits`.
fdoraybacba4a22017-05-10 21:10:00427
428```cpp
429// This task has no explicit TaskTraits. It cannot block. Its priority
430// is inherited from the calling context (e.g. if it is posted from
Gabriel Charette141a442582018-07-27 21:23:25431// a BEST_EFFORT task, it will have a BEST_EFFORT priority). It will either
fdoraybacba4a22017-05-10 21:10:00432// block shutdown or be skipped on shutdown.
433base::PostTask(FROM_HERE, base::BindOnce(...));
434
Gabriel Charette52fa3ae2019-04-15 21:44:37435// This task has the highest priority. The thread pool will try to
Gabriel Charette141a442582018-07-27 21:23:25436// run it before USER_VISIBLE and BEST_EFFORT tasks.
fdoraybacba4a22017-05-10 21:10:00437base::PostTaskWithTraits(
438 FROM_HERE, {base::TaskPriority::USER_BLOCKING},
439 base::BindOnce(...));
440
441// This task has the lowest priority and is allowed to block (e.g. it
442// can read a file from disk).
443base::PostTaskWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00444 FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
fdoraybacba4a22017-05-10 21:10:00445 base::BindOnce(...));
446
447// This task blocks shutdown. The process won't exit before its
448// execution is complete.
449base::PostTaskWithTraits(
450 FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
451 base::BindOnce(...));
Eric Seckler6cf08db82018-08-30 12:01:55452
453// This task will run on the Browser UI thread.
454base::PostTaskWithTraits(
455 FROM_HERE, {content::BrowserThread::UI},
456 base::BindOnce(...));
fdoraybacba4a22017-05-10 21:10:00457```
458
459## Keeping the Browser Responsive
460
461Do not perform expensive work on the main thread, the IO thread or any sequence
462that is expected to run tasks with a low latency. Instead, perform expensive
463work asynchronously using `base::PostTaskAndReply*()` or
Gabriel Charette90480312018-02-16 15:10:05464`SequencedTaskRunner::PostTaskAndReply()`. Note that asynchronous/overlapped
465I/O on the IO thread are fine.
fdoraybacba4a22017-05-10 21:10:00466
467Example: Running the code below on the main thread will prevent the browser from
468responding to user input for a long time.
469
470```cpp
471// GetHistoryItemsFromDisk() may block for a long time.
472// AddHistoryItemsToOmniboxDropDown() updates the UI and therefore must
473// be called on the main thread.
474AddHistoryItemsToOmniboxDropdown(GetHistoryItemsFromDisk("keyword"));
475```
476
477The code below solves the problem by scheduling a call to
478`GetHistoryItemsFromDisk()` in a thread pool followed by a call to
479`AddHistoryItemsToOmniboxDropdown()` on the origin sequence (the main thread in
480this case). The return value of the first call is automatically provided as
481argument to the second call.
482
483```cpp
484base::PostTaskWithTraitsAndReplyWithResult(
485 FROM_HERE, {base::MayBlock()},
486 base::BindOnce(&GetHistoryItemsFromDisk, "keyword"),
487 base::BindOnce(&AddHistoryItemsToOmniboxDropdown));
488```
489
490## Posting a Task with a Delay
491
492### Posting a One-Off Task with a Delay
493
494To post a task that must run once after a delay expires, use
495`base::PostDelayedTask*()` or `TaskRunner::PostDelayedTask()`.
496
497```cpp
498base::PostDelayedTaskWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00499 FROM_HERE, {base::TaskPriority::BEST_EFFORT}, base::BindOnce(&Task),
fdoraybacba4a22017-05-10 21:10:00500 base::TimeDelta::FromHours(1));
501
502scoped_refptr<base::SequencedTaskRunner> task_runner =
Gabriel Charetteb10aeeb2018-07-26 20:15:00503 base::CreateSequencedTaskRunnerWithTraits({base::TaskPriority::BEST_EFFORT});
fdoraybacba4a22017-05-10 21:10:00504task_runner->PostDelayedTask(
505 FROM_HERE, base::BindOnce(&Task), base::TimeDelta::FromHours(1));
506```
507
508*** note
509**NOTE:** A task that has a 1-hour delay probably doesn’t have to run right away
Gabriel Charetteb10aeeb2018-07-26 20:15:00510when its delay expires. Specify `base::TaskPriority::BEST_EFFORT` to prevent it
fdoraybacba4a22017-05-10 21:10:00511from slowing down the browser when its delay expires.
512***
513
514### Posting a Repeating Task with a Delay
515To post a task that must run at regular intervals,
516use [`base::RepeatingTimer`](https://cs.chromium.org/chromium/src/base/timer/timer.h).
517
518```cpp
519class A {
520 public:
521 ~A() {
522 // The timer is stopped automatically when it is deleted.
523 }
524 void StartDoingStuff() {
525 timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1),
526 this, &MyClass::DoStuff);
527 }
528 void StopDoingStuff() {
529 timer_.Stop();
530 }
531 private:
532 void DoStuff() {
533 // This method is called every second on the sequence that invoked
534 // StartDoingStuff().
535 }
536 base::RepeatingTimer timer_;
537};
538```
539
540## Cancelling a Task
541
542### Using base::WeakPtr
543
544[`base::WeakPtr`](https://cs.chromium.org/chromium/src/base/memory/weak_ptr.h)
545can be used to ensure that any callback bound to an object is canceled when that
546object is destroyed.
547
548```cpp
549int Compute() { … }
550
551class A {
552 public:
553 A() : weak_ptr_factory_(this) {}
554
555 void ComputeAndStore() {
556 // Schedule a call to Compute() in a thread pool followed by
557 // a call to A::Store() on the current sequence. The call to
558 // A::Store() is canceled when |weak_ptr_factory_| is destroyed.
559 // (guarantees that |this| will not be used-after-free).
560 base::PostTaskAndReplyWithResult(
561 FROM_HERE, base::BindOnce(&Compute),
562 base::BindOnce(&A::Store, weak_ptr_factory_.GetWeakPtr()));
563 }
564
565 private:
566 void Store(int value) { value_ = value; }
567
568 int value_;
569 base::WeakPtrFactory<A> weak_ptr_factory_;
570};
571```
572
573Note: `WeakPtr` is not thread-safe: `GetWeakPtr()`, `~WeakPtrFactory()`, and
574`Compute()` (bound to a `WeakPtr`) must all run on the same sequence.
575
576### Using base::CancelableTaskTracker
577
578[`base::CancelableTaskTracker`](https://cs.chromium.org/chromium/src/base/task/cancelable_task_tracker.h)
579allows cancellation to happen on a different sequence than the one on which
580tasks run. Keep in mind that `CancelableTaskTracker` cannot cancel tasks that
581have already started to run.
582
583```cpp
584auto task_runner = base::CreateTaskRunnerWithTraits(base::TaskTraits());
585base::CancelableTaskTracker cancelable_task_tracker;
586cancelable_task_tracker.PostTask(task_runner.get(), FROM_HERE,
Peter Kasting341e1fb2018-02-24 00:03:01587 base::DoNothing());
fdoraybacba4a22017-05-10 21:10:00588// Cancels Task(), only if it hasn't already started running.
589cancelable_task_tracker.TryCancelAll();
590```
591
592## Testing
593
594To test code that uses `base::ThreadTaskRunnerHandle`,
595`base::SequencedTaskRunnerHandle` or a function in
Gabriel Charette04b138f2018-08-06 00:03:22596[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h), instantiate a
fdoraybacba4a22017-05-10 21:10:00597[`base::test::ScopedTaskEnvironment`](https://cs.chromium.org/chromium/src/base/test/scoped_task_environment.h)
598for the scope of the test.
599
Wezd9e4cb772019-01-09 03:07:03600Tests can run the ScopedTaskEnvironment's message pump using a RunLoop, which
601can be made to run until Quit, or to execute ready-to-run tasks and immediately
602return.
603
604ScopedTaskEnvironment configures RunLoop::Run() to LOG(FATAL) if it hasn't been
605explicitly quit after TestTimeouts::action_timeout(). This is preferable to
606having the test hang if the code under test fails to trigger the RunLoop to
607quit. The timeout can be overridden with ScopedRunTimeoutForTest.
608
fdoraybacba4a22017-05-10 21:10:00609```cpp
610class MyTest : public testing::Test {
611 public:
612 // ...
613 protected:
614 base::test::ScopedTaskEnvironment scoped_task_environment_;
615};
616
617TEST(MyTest, MyTest) {
618 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&A));
619 base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
620 base::BindOnce(&B));
621 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
622 FROM_HERE, base::BindOnce(&C), base::TimeDelta::Max());
623
624 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until it is empty.
625 // Delayed tasks are not added to the queue until they are ripe for execution.
626 base::RunLoop().RunUntilIdle();
627 // A and B have been executed. C is not ripe for execution yet.
628
629 base::RunLoop run_loop;
630 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&D));
631 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure());
632 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&E));
633
634 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until QuitClosure is
635 // invoked.
636 run_loop.Run();
637 // D and run_loop.QuitClosure() have been executed. E is still in the queue.
638
Gabriel Charette52fa3ae2019-04-15 21:44:37639 // Tasks posted to thread pool run asynchronously as they are posted.
fdoraybacba4a22017-05-10 21:10:00640 base::PostTaskWithTraits(FROM_HERE, base::TaskTraits(), base::BindOnce(&F));
641 auto task_runner =
642 base::CreateSequencedTaskRunnerWithTraits(base::TaskTraits());
643 task_runner->PostTask(FROM_HERE, base::BindOnce(&G));
644
Gabriel Charette52fa3ae2019-04-15 21:44:37645 // To block until all tasks posted to thread pool are done running:
646 base::ThreadPool::GetInstance()->FlushForTesting();
fdoraybacba4a22017-05-10 21:10:00647 // F and G have been executed.
648
649 base::PostTaskWithTraitsAndReplyWithResult(
650 FROM_HERE, base::TaskTrait(),
651 base::BindOnce(&H), base::BindOnce(&I));
652
653 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until both the
654 // (Thread|Sequenced)TaskRunnerHandle queue and the TaskSchedule queue are
655 // empty:
656 scoped_task_environment_.RunUntilIdle();
657 // E, H, I have been executed.
658}
659```
660
Gabriel Charette52fa3ae2019-04-15 21:44:37661## Using ThreadPool in a New Process
fdoraybacba4a22017-05-10 21:10:00662
Gabriel Charette52fa3ae2019-04-15 21:44:37663ThreadPool needs to be initialized in a process before the functions in
Gabriel Charette04b138f2018-08-06 00:03:22664[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h)
Gabriel Charette52fa3ae2019-04-15 21:44:37665can be used. Initialization of ThreadPool in the Chrome browser process and
fdoraybacba4a22017-05-10 21:10:00666child processes (renderer, GPU, utility) has already been taken care of. To use
Gabriel Charette52fa3ae2019-04-15 21:44:37667ThreadPool in another process, initialize ThreadPool early in the main
fdoraybacba4a22017-05-10 21:10:00668function:
669
670```cpp
Gabriel Charette52fa3ae2019-04-15 21:44:37671// This initializes and starts ThreadPool with default params.
672base::ThreadPool::CreateAndStartWithDefaultParams(“process_name”);
Gabriel Charette04b138f2018-08-06 00:03:22673// The base/task/post_task.h API can now be used. Tasks will be // scheduled as
674// they are posted.
fdoraybacba4a22017-05-10 21:10:00675
Gabriel Charette52fa3ae2019-04-15 21:44:37676// This initializes ThreadPool.
677base::ThreadPool::Create(“process_name”);
Gabriel Charette04b138f2018-08-06 00:03:22678// The base/task/post_task.h API can now be used. No threads // will be created
679// and no tasks will be scheduled until after Start() is called.
Gabriel Charette52fa3ae2019-04-15 21:44:37680base::ThreadPool::GetInstance()->Start(params);
681// ThreadPool can now create threads and schedule tasks.
fdoraybacba4a22017-05-10 21:10:00682```
683
Gabriel Charette52fa3ae2019-04-15 21:44:37684And shutdown ThreadPool late in the main function:
fdoraybacba4a22017-05-10 21:10:00685
686```cpp
Gabriel Charette52fa3ae2019-04-15 21:44:37687base::ThreadPool::GetInstance()->Shutdown();
fdoraybacba4a22017-05-10 21:10:00688// Tasks posted with TaskShutdownBehavior::BLOCK_SHUTDOWN and
689// tasks posted with TaskShutdownBehavior::SKIP_ON_SHUTDOWN that
690// have started to run before the Shutdown() call have now completed their
691// execution. Tasks posted with
692// TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN may still be
693// running.
694```
Gabriel Charetteb86e5fe62017-06-08 19:39:28695## TaskRunner ownership (encourage no dependency injection)
Sebastien Marchandc95489b2017-05-25 16:39:34696
697TaskRunners shouldn't be passed through several components. Instead, the
698components that uses a TaskRunner should be the one that creates it.
699
700See [this example](https://codereview.chromium.org/2885173002/) of a
701refactoring where a TaskRunner was passed through a lot of components only to be
702used in an eventual leaf. The leaf can and should now obtain its TaskRunner
703directly from
Gabriel Charette04b138f2018-08-06 00:03:22704[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h).
Gabriel Charetteb86e5fe62017-06-08 19:39:28705
706Dependency injection of TaskRunners can still seldomly be useful to unit test a
707component when triggering a specific race in a specific way is essential to the
708test. For such cases the preferred approach is the following:
709
710```cpp
711class FooWithCustomizableTaskRunnerForTesting {
712 public:
713
714 void SetBackgroundTaskRunnerForTesting(
michaelpg12c04572017-06-26 23:25:06715 scoped_refptr<base::SequencedTaskRunner> background_task_runner);
Gabriel Charetteb86e5fe62017-06-08 19:39:28716
717 private:
michaelpg12c04572017-06-26 23:25:06718 scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
719 base::CreateSequencedTaskRunnerWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00720 {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
Gabriel Charetteb86e5fe62017-06-08 19:39:28721}
722```
723
724Note that this still allows removing all layers of plumbing between //chrome and
725that component since unit tests will use the leaf layer directly.
Gabriel Charette8917f4c2018-11-22 15:50:28726
727## FAQ
728See [Threading and Tasks FAQ](threading_and_tasks_faq.md) for more examples.