blob: 0084fcdc532bc67567c16e4d0c348758f5c9d85d [file] [log] [blame] [view]
Francois Doraycc49b74d2018-10-09 13:49:091# Threading and Tasks in Chrome - FAQ
2
3[TOC]
4
5## General
6
7### On what thread will a task run?
8
9A task is posted through the `base/task/post_task.h` API with `TaskTraits`.
10
11* If `TaskTraits` contain `BrowserThread::UI`:
12 * The task runs on the main thread.
13
14* If `TaskTraits` contain `BrowserThread::IO`:
15 * The task runs on the IO thread.
16
17* If `TaskTraits` don't contain `BrowserThread::UI/IO`:
18 * If the task is posted through a `SingleThreadTaskRunner` obtained from
19 `CreateSingleThreadTaskRunnerWithTraits(..., mode)`:
20 * Where `mode` is `SingleThreadTaskRunnerThreadMode::DEDICATED`:
21 * The task runs on a thread that only runs tasks from that
22 SingleThreadTaskRunner. This is not the main thread or the IO
23 thread.
24
25 * Where `mode` is `SingleThreadTaskRunnerThreadMode::SHARED`:
26 * The task runs on a thread that runs tasks from one or many
27 unrelated SingleThreadTaskRunners. This is not the main thread
28 or the IO thread.
29
30 * Otherwise:
31 * The task runs in a thread pool.
32
33As explained in [Prefer Sequences to Threads](threading_and_tasks.md#Prefer-Sequences-to-Threads),
34tasks should generally run on a sequence in a thread pool rather than on a
35dedicated thread.
36
37## Blocking off-CPU
38
39### How to make a call that may block off-CPU and never return?
40
41If you can't avoid making a call to a third-party library that may block off-CPU
42and never return, you must take some steps to ensure that it doesn't prevent
43other tasks from running. The steps depend on where the task runs (see [Where
44will a task run?](#On-what-thread-will-a-task-run_)).
45
46If the task runs in a thread pool:
47
48* Annotate the scope that may block off-CPU with
49 `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
53 capacity goes back to normal. Since tasks posted to the same sequence can't
54 run concurrently, it is advisable to run tasks that may block indefinitely in
55 [parallel](threading_and_tasks.md#posting-a-parallel-task) rather than in
56 [sequence](threading_and_tasks.md#posting-a-sequenced-task).
57
58If the task runs on the main thread, the IO thread or a `SHARED
59SingleThreadTaskRunner`:
60
61* Blocking on one of these threads will cause breakages. Move your task to a
62 thread pool (or to a `DEDICATED SingleThreadTaskRunner` if necessary - see
63 [Prefer Sequences to Threads](threading_and_tasks.md#Prefer-Sequences-to-Threads)).
64
65If the task runs on a `DEDICATED SingleThreadTaskRunner`:
66
67* Annotate the scope that may block off-CPU with
68 `ScopedBlockingCall(BlockingType::MAY_BLOCK/WILL_BLOCK)`. The annotation is a
69 no-op that documents the blocking behavior. Tasks posted to the same
70 `DEDICATED SingleThreadTaskRunner` won't run until your blocking task returns
71 (they will never run if the blocking task never returns).
72
73`[base/threading/scoped_blocking_call.h](https://cs.chromium.org/chromium/src/base/threading/scoped_blocking_call.h)`
74explains the difference between `MAY_BLOCK ` and `WILL_BLOCK` and gives
75examples of off-CPU blocking operations.
76
77## Sequences
78
79### How to migrate from SingleThreadTaskRunner to SequencedTaskRunner?
80
81The following mappings can be useful when migrating code from a
82`SingleThreadTaskRunner` to a `SequencedTaskRunner`:
83
84* base::SingleThreadTaskRunner -> base::SequencedTaskRunner
85 * SingleThreadTaskRunner::BelongsToCurrentThread() -> SequencedTaskRunner::RunsTasksInCurrentSequence()
86* base::ThreadTaskRunnerHandle -> base::SequencedTaskRunnerHandle
87* THREAD_CHECKER -> SEQUENCE_CHECKER
88* base::ThreadLocalStorage::Slot -> base::SequenceLocalStorageSlot
89* BrowserThread::DeleteOnThread -> base::OnTaskRunnerDeleter / base::RefCountedDeleteOnSequence
90* BrowserMessageFilter::OverrideThreadForMessage() -> BrowserMessageFilter::OverrideTaskRunnerForMessage()
91* CreateSingleThreadTaskRunnerWithTraits() -> CreateSequencedTaskRunnerWithTraits()
92 * Every CreateSingleThreadTaskRunnerWithTraits() usage should be accompanied
93 with a comment and ideally a bug to make it sequence when the sequence-unfriendly
94 dependency is addressed.
95
96### How to ensure mutual exclusion between tasks posted by a component?
97
98Create a `SequencedTaskRunner` using `CreateSequencedTaskRunnerWithTraits()` and
99store it on an object that can be accessed from all the PostTask() call sites
100that require mutual exclusion. If there isn't a shared object that can own
101common `SequencedTaskRunner`, use
102`Lazy(Sequenced|SingleThread|COMSTA)TaskRunner` in an anonymous namespace.
103
104## Tests
105
106### How to test code that posts tasks?
107
108If the test uses `BrowserThread::UI/IO`, instantiate a
109`content::TestBrowserThreadBundle` for the scope of the test. Call
110`content::RunAllTasksUntilIdle()` to wait until all tasks have run.
111
112If the test doesn't use `BrowserThread::UI/IO`, instantiate a
113`base::test::ScopedTaskEnvironment` for the scope of the test. Call
114`base::test::ScopedTaskEnvironment::RunUntilIdle()` to wait until all tasks have
115run.
116
117In both cases, you can run tasks until a condition is met. A test that waits for
118a condition to be met is easier to understand and debug than a test that waits
119for all tasks to run.
120
121```cpp
122int g_condition = false;
123
124base::RunLoop run_loop;
125base::PostTaskWithTraits(FROM_HERE, {}, base::BindOnce(
126 [] (base::OnceClosure closure) {
127 g_condition = true;
128 std::move(quit_closure).Run();
129 }, run_loop.QuitClosure()));
130
131// Runs tasks until the quit closure is invoked.
132run_loop.Run();
133
134EXPECT_TRUE(g_condition);
135```
136
137## Your question hasn't been answered?
138
139Ping
140[scheduler-dev@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/scheduler-dev).