blob: ac918435909d3568d1680ffe647ca55e86f0200c [file] [log] [blame] [view]
Francois Doraycc49b74d2018-10-09 13:49:091# Threading and Tasks in Chrome - FAQ
2
3[TOC]
4
Gabriel Charette8917f4c2018-11-22 15:50:285Note: Make sure to read the main [Threading and Tasks](threading_and_tasks.md)
6docs first.
7
Francois Doraycc49b74d2018-10-09 13:49:098## General
9
Gabriel Charette8917f4c2018-11-22 15:50:2810### On which thread will a task run?
Francois Doraycc49b74d2018-10-09 13:49:0911
12A task is posted through the `base/task/post_task.h` API with `TaskTraits`.
13
14* If `TaskTraits` contain `BrowserThread::UI`:
15 * The task runs on the main thread.
16
17* If `TaskTraits` contain `BrowserThread::IO`:
18 * The task runs on the IO thread.
19
20* If `TaskTraits` don't contain `BrowserThread::UI/IO`:
21 * If the task is posted through a `SingleThreadTaskRunner` obtained from
22 `CreateSingleThreadTaskRunnerWithTraits(..., mode)`:
23 * Where `mode` is `SingleThreadTaskRunnerThreadMode::DEDICATED`:
24 * The task runs on a thread that only runs tasks from that
Gabriel Charette8917f4c2018-11-22 15:50:2825 SingleThreadTaskRunner. This is not the main thread nor the IO
Francois Doraycc49b74d2018-10-09 13:49:0926 thread.
27
28 * Where `mode` is `SingleThreadTaskRunnerThreadMode::SHARED`:
29 * The task runs on a thread that runs tasks from one or many
30 unrelated SingleThreadTaskRunners. This is not the main thread
Gabriel Charette8917f4c2018-11-22 15:50:2831 nor the IO thread.
Francois Doraycc49b74d2018-10-09 13:49:0932
33 * Otherwise:
34 * The task runs in a thread pool.
35
36As explained in [Prefer Sequences to Threads](threading_and_tasks.md#Prefer-Sequences-to-Threads),
37tasks should generally run on a sequence in a thread pool rather than on a
38dedicated thread.
39
Gabriel Charette8917f4c2018-11-22 15:50:2840## Making blocking calls (which do not use the CPU)
Francois Doraycc49b74d2018-10-09 13:49:0941
Etienne Pierre-dorayd710e152018-10-26 16:22:2342### How to make a blocking call without preventing other tasks from being scheduled?
Francois Doraycc49b74d2018-10-09 13:49:0943
Etienne Pierre-dorayd710e152018-10-26 16:22:2344The steps depend on where the task runs (see [Where will a task run?](#On-what-thread-will-a-task-run_)).
Francois Doraycc49b74d2018-10-09 13:49:0945
46If the task runs in a thread pool:
47
Gabriel Charette8917f4c2018-11-22 15:50:2848* Annotate the scope that may block with
Francois Doraycc49b74d2018-10-09 13:49:0949 `ScopedBlockingCall(BlockingType::MAY_BLOCK/WILL_BLOCK)`. A few milliseconds
50 after the annotated scope is entered, the capacity of the thread pool is
51 incremented. This ensures that your task doesn't reduce the number of tasks
52 that can run concurrently on the CPU. If the scope exits, the thread pool
Etienne Pierre-dorayd710e152018-10-26 16:22:2353 capacity goes back to normal.
Francois Doraycc49b74d2018-10-09 13:49:0954
55If the task runs on the main thread, the IO thread or a `SHARED
56SingleThreadTaskRunner`:
57
58* Blocking on one of these threads will cause breakages. Move your task to a
59 thread pool (or to a `DEDICATED SingleThreadTaskRunner` if necessary - see
60 [Prefer Sequences to Threads](threading_and_tasks.md#Prefer-Sequences-to-Threads)).
61
62If the task runs on a `DEDICATED SingleThreadTaskRunner`:
63
Gabriel Charette8917f4c2018-11-22 15:50:2864* Annotate the scope that may block with
Francois Doraycc49b74d2018-10-09 13:49:0965 `ScopedBlockingCall(BlockingType::MAY_BLOCK/WILL_BLOCK)`. The annotation is a
Gabriel Charette8917f4c2018-11-22 15:50:2866 no-op that documents the blocking behavior (and makes it pass assertions).
67 Tasks posted to the same `DEDICATED SingleThreadTaskRunner` won't run until
68 your blocking task returns (they will never run if the blocking task never
69 returns).
Francois Doraycc49b74d2018-10-09 13:49:0970
Etienne Pierre-doray338d61c2018-10-16 12:35:3271[base/threading/scoped_blocking_call.h](https://cs.chromium.org/chromium/src/base/threading/scoped_blocking_call.h)
Francois Doraycc49b74d2018-10-09 13:49:0972explains the difference between `MAY_BLOCK ` and `WILL_BLOCK` and gives
Gabriel Charette8917f4c2018-11-22 15:50:2873examples of blocking operations.
Francois Doraycc49b74d2018-10-09 13:49:0974
Etienne Pierre-dorayd710e152018-10-26 16:22:2375### How to make a blocking call that may never return without preventing other tasks from being scheduled?
76
77If you can't avoid making a call to a third-party library that may block off-
78CPU, follow recommendations in [How to make a blocking call without affecting
79other tasks?](#How-to-make-a-blocking-call-without-affecting-other-tasks_).
80This ensures that a current task doesn't prevent other tasks from running even
81if it never returns.
82
83Since tasks posted to the same sequence can't run concurrently, it is advisable
84to run tasks that may block indefinitely in
85[parallel](threading_and_tasks.md#posting-a-parallel-task) rather than in
Gabriel Charette8917f4c2018-11-22 15:50:2886[sequence](threading_and_tasks.md#posting-a-sequenced-task) (unless posting many
87such tasks at which point sequencing can be a useful tool to prevent flooding).
Etienne Pierre-dorayd710e152018-10-26 16:22:2388
Etienne Pierre-doray338d61c2018-10-16 12:35:3289### Do calls to blocking //base APIs need to be annotated with ScopedBlockingCall?
90
91No. All blocking //base APIs (e.g. base::ReadFileToString, base::File::Read,
92base::SysInfo::AmountOfFreeDiskSpace, base::WaitableEvent::Wait, etc.) have their
93own internal annotations. See
94[base/threading/scoped_blocking_call.h](https://cs.chromium.org/chromium/src/base/threading/scoped_blocking_call.h).
95
96### Can multiple ScopedBlockingCall be nested for the purpose of documentation?
97
98Nested `ScopedBlockingCall` are supported. Most of the time, the inner
99ScopedBlockingCalls will no-op (the exception is WILL_BLOCK nested in MAY_BLOCK).
100As such, it is permitted to add a ScopedBlockingCall in the scope where a function
101that is already annotated is called for documentation purposes.:
102
103```cpp
104Data GetDataFromNetwork() {
105 ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
106 // Fetch data from network.
107 ...
108 return data;
109}
110
111void ProcessDataFromNetwork() {
112 Data data;
113 {
114 // Document the blocking behavior with a ScopedBlockingCall.
115 // Permitted, but not required since GetDataFromNetwork() is itself annotated.
116 ScopedBlockingCall scoped_blocking_call(BlockingType::MAY_BLOCK);
117 data = GetDataFromNetwork();
118 }
119 CPUIntensiveProcessing(data);
120}
121```
122
123 However, CPU usage should always be minimal within the scope of
124`ScopedBlockingCall`. See
125[base/threading/scoped_blocking_call.h](https://cs.chromium.org/chromium/src/base/threading/scoped_blocking_call.h).
126
127
Francois Doraycc49b74d2018-10-09 13:49:09128## Sequences
129
130### How to migrate from SingleThreadTaskRunner to SequencedTaskRunner?
131
132The following mappings can be useful when migrating code from a
133`SingleThreadTaskRunner` to a `SequencedTaskRunner`:
134
135* base::SingleThreadTaskRunner -> base::SequencedTaskRunner
136 * SingleThreadTaskRunner::BelongsToCurrentThread() -> SequencedTaskRunner::RunsTasksInCurrentSequence()
137* base::ThreadTaskRunnerHandle -> base::SequencedTaskRunnerHandle
138* THREAD_CHECKER -> SEQUENCE_CHECKER
139* base::ThreadLocalStorage::Slot -> base::SequenceLocalStorageSlot
140* BrowserThread::DeleteOnThread -> base::OnTaskRunnerDeleter / base::RefCountedDeleteOnSequence
141* BrowserMessageFilter::OverrideThreadForMessage() -> BrowserMessageFilter::OverrideTaskRunnerForMessage()
142* CreateSingleThreadTaskRunnerWithTraits() -> CreateSequencedTaskRunnerWithTraits()
Gabriel Charette8917f4c2018-11-22 15:50:28143 * Every CreateSingleThreadTaskRunnerWithTraits() usage, outside of
144 BrowserThread::UI/IO, should be accompanied with a comment and ideally a
145 bug to make it sequence when the sequence-unfriendly dependency is
146 addressed.
Francois Doraycc49b74d2018-10-09 13:49:09147
148### How to ensure mutual exclusion between tasks posted by a component?
149
150Create a `SequencedTaskRunner` using `CreateSequencedTaskRunnerWithTraits()` and
151store it on an object that can be accessed from all the PostTask() call sites
Gabriel Charette8917f4c2018-11-22 15:50:28152that require mutual exclusion. If there isn't a shared object that can own a
Francois Doraycc49b74d2018-10-09 13:49:09153common `SequencedTaskRunner`, use
154`Lazy(Sequenced|SingleThread|COMSTA)TaskRunner` in an anonymous namespace.
155
156## Tests
157
158### How to test code that posts tasks?
159
160If the test uses `BrowserThread::UI/IO`, instantiate a
161`content::TestBrowserThreadBundle` for the scope of the test. Call
Gabriel Charette8917f4c2018-11-22 15:50:28162`TestBrowserThreadBundle::RunUntilIdle()` to wait until all tasks have run.
Francois Doraycc49b74d2018-10-09 13:49:09163
164If the test doesn't use `BrowserThread::UI/IO`, instantiate a
165`base::test::ScopedTaskEnvironment` for the scope of the test. Call
166`base::test::ScopedTaskEnvironment::RunUntilIdle()` to wait until all tasks have
167run.
168
169In both cases, you can run tasks until a condition is met. A test that waits for
170a condition to be met is easier to understand and debug than a test that waits
171for all tasks to run.
172
173```cpp
174int g_condition = false;
175
176base::RunLoop run_loop;
177base::PostTaskWithTraits(FROM_HERE, {}, base::BindOnce(
178 [] (base::OnceClosure closure) {
179 g_condition = true;
180 std::move(quit_closure).Run();
181 }, run_loop.QuitClosure()));
182
183// Runs tasks until the quit closure is invoked.
184run_loop.Run();
185
186EXPECT_TRUE(g_condition);
187```
188
189## Your question hasn't been answered?
190
Gabriel Charette8917f4c2018-11-22 15:50:28191 1. Check the main [Threading and Tasks](threading_and_tasks.md) docs.
192 2. Ping
Francois Doraycc49b74d2018-10-09 13:49:09193[scheduler-dev@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/scheduler-dev).