blob: 694df67c136403db8b7a2c8f6ce94fdab7ff3112 [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
fdoraybacba4a22017-05-10 21:10:0018### Threads
19
20Every Chrome process has
21
22* a main thread
23 * in the browser process: updates the UI
24 * in renderer processes: runs most of Blink
25* an IO thread
26 * in the browser process: handles IPCs and network requests
27 * in renderer processes: handles IPCs
28* a few more special-purpose threads
29* and a pool of general-purpose threads
30
31Most threads have a loop that gets tasks from a queue and runs them (the queue
32may be shared between multiple threads).
33
34### Tasks
35
36A task is a `base::OnceClosure` added to a queue for asynchronous execution.
37
38A `base::OnceClosure` stores a function pointer and arguments. It has a `Run()`
39method that invokes the function pointer using the bound arguments. It is
40created using `base::BindOnce`. (ref. [Callback<> and Bind()
41documentation](callback.md)).
42
43```
44void TaskA() {}
45void TaskB(int v) {}
46
47auto task_a = base::BindOnce(&TaskA);
48auto task_b = base::BindOnce(&TaskB, 42);
49```
50
51A group of tasks can be executed in one of the following ways:
52
53* [Parallel](#Posting-a-Parallel-Task): No task execution ordering, possibly all
54 at once on any thread
55* [Sequenced](#Posting-a-Sequenced-Task): Tasks executed in posting order, one
56 at a time on any thread.
57* [Single Threaded](#Posting-Multiple-Tasks-to-the-Same-Thread): Tasks executed
58 in posting order, one at a time on a single thread.
59 * [COM Single Threaded](#Posting-Tasks-to-a-COM-Single-Thread-Apartment-STA_Thread-Windows_):
60 A variant of single threaded with COM initialized.
61
gab2a4576052017-06-07 23:36:1262### Prefer Sequences to Threads
63
Gabriel Charetteb86e5fe62017-06-08 19:39:2864**Sequenced execution mode is far preferred to Single Threaded** in scenarios
gab2a4576052017-06-07 23:36:1265that require mere thread-safety as it opens up scheduling paradigms that
66wouldn't be possible otherwise (sequences can hop threads instead of being stuck
67behind unrelated work on a dedicated thread). Ability to hop threads also means
68the thread count can dynamically adapt to the machine's true resource
Gabriel Charette90480312018-02-16 15:10:0569availability (increased parallelism on bigger machines, avoids trashing
70resources on smaller machines).
gab2a4576052017-06-07 23:36:1271
72Many core APIs were recently made sequence-friendly (classes are rarely
73thread-affine -- i.e. only when using thread-local-storage or third-party APIs
74that do). But the codebase has long evolved assuming single-threaded contexts...
75If your class could run on a sequence but is blocked by an overzealous use of
76ThreadChecker/ThreadTaskRunnerHandle/SingleThreadTaskRunner in a leaf
77dependency, consider fixing that dependency for everyone's benefit (or at the
78very least file a blocking bug against https://crbug.com/675631 and flag your
79use of base::CreateSingleThreadTaskRunnerWithTraits() with a TODO against your
80bug to use base::CreateSequencedTaskRunnerWithTraits() when fixed).
81
Gabriel Charette01567ac2017-06-09 15:31:1082Detailed documentation on how to migrate from single-threaded contexts to
Gabriel Charette8917f4c2018-11-22 15:50:2883sequenced contexts can be found [here](threading_and_tasks_faq.md#How-to-migrate-from-SingleThreadTaskRunner-to-SequencedTaskRunner).
Gabriel Charette01567ac2017-06-09 15:31:1084
gab2a4576052017-06-07 23:36:1285The discussion below covers all of these ways to execute tasks in details.
fdoraybacba4a22017-05-10 21:10:0086
87## Posting a Parallel Task
88
89### Direct Posting to the Task Scheduler
90
91A task that can run on any thread and doesn’t have ordering or mutual exclusion
92requirements with other tasks should be posted using one of the
93`base::PostTask*()` functions defined in
Gabriel Charette04b138f2018-08-06 00:03:2294[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h).
fdoraybacba4a22017-05-10 21:10:0095
96```cpp
97base::PostTask(FROM_HERE, base::BindOnce(&Task));
98```
99
100This posts tasks with default traits.
101
102The `base::PostTask*WithTraits()` functions allow the caller to provide
103additional details about the task via TaskTraits (ref.
104[Annotating Tasks with TaskTraits](#Annotating-Tasks-with-TaskTraits)).
105
106```cpp
107base::PostTaskWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00108 FROM_HERE, {base::TaskPriority::BEST_EFFORT, MayBlock()},
fdoraybacba4a22017-05-10 21:10:00109 base::BindOnce(&Task));
110```
111
fdoray52bf5552017-05-11 12:43:59112### Posting via a TaskRunner
fdoraybacba4a22017-05-10 21:10:00113
114A parallel
115[`TaskRunner`](https://cs.chromium.org/chromium/src/base/task_runner.h) is an
116alternative to calling `base::PostTask*()` directly. This is mainly useful when
117it isn’t known in advance whether tasks will be posted in parallel, in sequence,
fdoray52bf5552017-05-11 12:43:59118or to a single-thread (ref.
119[Posting a Sequenced Task](#Posting-a-Sequenced-Task),
120[Posting Multiple Tasks to the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread)).
121Since `TaskRunner` is the base class of `SequencedTaskRunner` and
122`SingleThreadTaskRunner`, a `scoped_refptr<TaskRunner>` member can hold a
fdoraybacba4a22017-05-10 21:10:00123`TaskRunner`, a `SequencedTaskRunner` or a `SingleThreadTaskRunner`.
124
125```cpp
126class A {
127 public:
128 A() = default;
129
130 void set_task_runner_for_testing(
131 scoped_refptr<base::TaskRunner> task_runner) {
132 task_runner_ = std::move(task_runner);
133 }
134
135 void DoSomething() {
136 // In production, A is always posted in parallel. In test, it is posted to
137 // the TaskRunner provided via set_task_runner_for_testing().
138 task_runner_->PostTask(FROM_HERE, base::BindOnce(&A));
139 }
140
141 private:
142 scoped_refptr<base::TaskRunner> task_runner_ =
143 base::CreateTaskRunnerWithTraits({base::TaskPriority::USER_VISIBLE});
144};
145```
146
147Unless a test needs to control precisely how tasks are executed, it is preferred
148to call `base::PostTask*()` directly (ref. [Testing](#Testing) for less invasive
149ways of controlling tasks in tests).
150
151## Posting a Sequenced Task
152
153A sequence is a set of tasks that run one at a time in posting order (not
154necessarily on the same thread). To post tasks as part of a sequence, use a
Gabriel Charette90480312018-02-16 15:10:05155[`SequencedTaskRunner`](https://cs.chromium.org/chromium/src/base/sequenced_task_runner.h).
fdoraybacba4a22017-05-10 21:10:00156
157### Posting to a New Sequence
158
159A `SequencedTaskRunner` can be created by
160`base::CreateSequencedTaskRunnerWithTraits()`.
161
162```cpp
163scoped_refptr<SequencedTaskRunner> sequenced_task_runner =
164 base::CreateSequencedTaskRunnerWithTraits(...);
165
166// TaskB runs after TaskA completes.
167sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA));
168sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB));
169```
170
171### Posting to the Current Sequence
172
173The `SequencedTaskRunner` to which the current task was posted can be obtained
174via
175[`SequencedTaskRunnerHandle::Get()`](https://cs.chromium.org/chromium/src/base/threading/sequenced_task_runner_handle.h).
176
177*** note
178**NOTE:** it is invalid to call `SequencedTaskRunnerHandle::Get()` from a
179parallel task, but it is valid from a single-threaded task (a
180`SingleThreadTaskRunner` is a `SequencedTaskRunner`).
181***
182
183```cpp
184// The task will run after any task that has already been posted
185// to the SequencedTaskRunner to which the current task was posted
186// (in particular, it will run after the current task completes).
187// It is also guaranteed that it won’t run concurrently with any
188// task posted to that SequencedTaskRunner.
189base::SequencedTaskRunnerHandle::Get()->
190 PostTask(FROM_HERE, base::BindOnce(&Task));
191```
192
193## Using Sequences Instead of Locks
194
195Usage of locks is discouraged in Chrome. Sequences inherently provide
Gabriel Charettea3ccc972018-11-13 14:43:12196thread-safety. Prefer classes that are always accessed from the same
197sequence to managing your own thread-safety with locks.
198
199**Thread-safe but not thread-affine; how so?** Tasks posted to the same sequence
200will run in sequential order. After a sequenced task completes, the next task
201may be picked up by a different worker thread, but that task is guaranteed to
202see any side-effects caused by the previous one(s) on its sequence.
fdoraybacba4a22017-05-10 21:10:00203
204```cpp
205class A {
206 public:
207 A() {
208 // Do not require accesses to be on the creation sequence.
isherman8c33b8a2017-06-27 19:18:30209 DETACH_FROM_SEQUENCE(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00210 }
211
212 void AddValue(int v) {
213 // Check that all accesses are on the same sequence.
isherman8c33b8a2017-06-27 19:18:30214 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00215 values_.push_back(v);
216}
217
218 private:
isherman8c33b8a2017-06-27 19:18:30219 SEQUENCE_CHECKER(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00220
221 // No lock required, because all accesses are on the
222 // same sequence.
223 std::vector<int> values_;
224};
225
226A a;
227scoped_refptr<SequencedTaskRunner> task_runner_for_a = ...;
Mike Bjorged3a09842018-05-15 18:37:28228task_runner_for_a->PostTask(FROM_HERE,
229 base::BindOnce(&A::AddValue, base::Unretained(&a), 42));
230task_runner_for_a->PostTask(FROM_HERE,
231 base::BindOnce(&A::AddValue, base::Unretained(&a), 27));
fdoraybacba4a22017-05-10 21:10:00232
233// Access from a different sequence causes a DCHECK failure.
234scoped_refptr<SequencedTaskRunner> other_task_runner = ...;
235other_task_runner->PostTask(FROM_HERE,
Mike Bjorged3a09842018-05-15 18:37:28236 base::BindOnce(&A::AddValue, base::Unretained(&a), 1));
fdoraybacba4a22017-05-10 21:10:00237```
238
Gabriel Charette90480312018-02-16 15:10:05239Locks should only be used to swap in a shared data structure that can be
240accessed on multiple threads. If one thread updates it based on expensive
241computation or through disk access, then that slow work should be done without
242holding on to the lock. Only when the result is available should the lock be
243used to swap in the new data. An example of this is in PluginList::LoadPlugins
244([`content/common/plugin_list.cc`](https://cs.chromium.org/chromium/src/content/
245common/plugin_list.cc). If you must use locks,
246[here](https://www.chromium.org/developers/lock-and-condition-variable) are some
247best practices and pitfalls to avoid.
248
249In order to write non-blocking code, many APIs in Chromium are asynchronous.
250Usually this means that they either need to be executed on a particular
251thread/sequence and will return results via a custom delegate interface, or they
252take a `base::Callback<>` object that is called when the requested operation is
253completed. Executing work on a specific thread/sequence is covered in the
254PostTask sections above.
255
fdoraybacba4a22017-05-10 21:10:00256## Posting Multiple Tasks to the Same Thread
257
258If multiple tasks need to run on the same thread, post them to a
259[`SingleThreadTaskRunner`](https://cs.chromium.org/chromium/src/base/single_thread_task_runner.h).
260All tasks posted to the same `SingleThreadTaskRunner` run on the same thread in
261posting order.
262
263### Posting to the Main Thread or to the IO Thread in the Browser Process
264
Eric Seckler6cf08db82018-08-30 12:01:55265To post tasks to the main thread or to the IO thread, use
266`base::PostTaskWithTraits()` or get the appropriate SingleThreadTaskRunner using
267`base::CreateSingleThreadTaskRunnerWithTraits`, supplying a `BrowserThread::ID`
268as trait. For this, you'll also need to include
269[`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:00270
271```cpp
Eric Seckler6cf08db82018-08-30 12:01:55272base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, ...);
fdoraybacba4a22017-05-10 21:10:00273
Eric Seckler6cf08db82018-08-30 12:01:55274base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})
fdoraybacba4a22017-05-10 21:10:00275 ->PostTask(FROM_HERE, ...);
276```
277
278The main thread and the IO thread are already super busy. Therefore, prefer
fdoray52bf5552017-05-11 12:43:59279posting to a general purpose thread when possible (ref.
280[Posting a Parallel Task](#Posting-a-Parallel-Task),
281[Posting a Sequenced task](#Posting-a-Sequenced-Task)).
282Good reasons to post to the main thread are to update the UI or access objects
283that are bound to it (e.g. `Profile`). A good reason to post to the IO thread is
284to access the internals of components that are bound to it (e.g. IPCs, network).
285Note: It is not necessary to have an explicit post task to the IO thread to
286send/receive an IPC or send/receive data on the network.
fdoraybacba4a22017-05-10 21:10:00287
288### Posting to the Main Thread in a Renderer Process
289TODO
290
291### Posting to a Custom SingleThreadTaskRunner
292
293If multiple tasks need to run on the same thread and that thread doesn’t have to
294be the main thread or the IO thread, post them to a `SingleThreadTaskRunner`
295created by `base::CreateSingleThreadTaskRunnerWithTraits`.
296
297```cpp
298scoped_refptr<SequencedTaskRunner> single_thread_task_runner =
299 base::CreateSingleThreadTaskRunnerWithTraits(...);
300
301// TaskB runs after TaskA completes. Both tasks run on the same thread.
302single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA));
303single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB));
304```
305
306*** note
307**IMPORTANT:** You should rarely need this, most classes in Chromium require
308thread-safety (which sequences provide) not thread-affinity. If an API you’re
309using is incorrectly thread-affine (i.e. using
310[`base::ThreadChecker`](https://cs.chromium.org/chromium/src/base/threading/thread_checker.h)
311when it’s merely thread-unsafe and should use
312[`base::SequenceChecker`](https://cs.chromium.org/chromium/src/base/sequence_checker.h)),
313please consider fixing it instead of making things worse by also making your API thread-affine.
314***
315
316### Posting to the Current Thread
317
318*** note
319**IMPORTANT:** To post a task that needs mutual exclusion with the current
320sequence of tasks but doesn’t absolutely need to run on the current thread, use
321`SequencedTaskRunnerHandle::Get()` instead of `ThreadTaskRunnerHandle::Get()`
322(ref. [Posting to the Current Sequence](#Posting-to-the-Current-Sequence)). That
323will better document the requirements of the posted task. In a single-thread
324task, `SequencedTaskRunnerHandle::Get()` is equivalent to
325`ThreadTaskRunnerHandle::Get()`.
326***
327
328To post a task to the current thread, use [`ThreadTaskRunnerHandle`](https://cs.chromium.org/chromium/src/base/threading/thread_task_runner_handle.h).
329
330```cpp
331// The task will run on the current thread in the future.
332base::ThreadTaskRunnerHandle::Get()->PostTask(
333 FROM_HERE, base::BindOnce(&Task));
334```
335
336*** note
337**NOTE:** It is invalid to call `ThreadTaskRunnerHandle::Get()` from a parallel
338or a sequenced task.
339***
340
341## Posting Tasks to a COM Single-Thread Apartment (STA) Thread (Windows)
342
343Tasks that need to run on a COM Single-Thread Apartment (STA) thread must be
344posted to a `SingleThreadTaskRunner` returned by
345`CreateCOMSTATaskRunnerWithTraits()`. As mentioned in [Posting Multiple Tasks to
346the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread), all tasks posted
347to the same `SingleThreadTaskRunner` run on the same thread in posting order.
348
349```cpp
350// Task(A|B|C)UsingCOMSTA will run on the same COM STA thread.
351
352void TaskAUsingCOMSTA() {
353 // [ This runs on a COM STA thread. ]
354
355 // Make COM STA calls.
356 // ...
357
358 // Post another task to the current COM STA thread.
359 base::ThreadTaskRunnerHandle::Get()->PostTask(
360 FROM_HERE, base::BindOnce(&TaskCUsingCOMSTA));
361}
362void TaskBUsingCOMSTA() { }
363void TaskCUsingCOMSTA() { }
364
365auto com_sta_task_runner = base::CreateCOMSTATaskRunnerWithTraits(...);
366com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskAUsingCOMSTA));
367com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskBUsingCOMSTA));
368```
369
370## Annotating Tasks with TaskTraits
371
Gabriel Charette04b138f2018-08-06 00:03:22372[`TaskTraits`](https://cs.chromium.org/chromium/src/base/task/task_traits.h)
fdoraybacba4a22017-05-10 21:10:00373encapsulate information about a task that helps the task scheduler make better
374scheduling decisions.
375
376All `PostTask*()` functions in
Gabriel Charette04b138f2018-08-06 00:03:22377[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h)
fdoraybacba4a22017-05-10 21:10:00378have an overload that takes `TaskTraits` as argument and one that doesn’t. The
379overload that doesn’t take `TaskTraits` as argument is appropriate for tasks
380that:
381- Don’t block (ref. MayBlock and WithBaseSyncPrimitives).
382- Prefer inheriting the current priority to specifying their own.
383- Can either block shutdown or be skipped on shutdown (task scheduler is free to choose a fitting default).
384Tasks that don’t match this description must be posted with explicit TaskTraits.
385
Gabriel Charette04b138f2018-08-06 00:03:22386[`base/task/task_traits.h`](https://cs.chromium.org/chromium/src/base/task/task_traits.h)
Eric Seckler6cf08db82018-08-30 12:01:55387provides exhaustive documentation of available traits. The content layer also
388provides additional traits in
389[`content/public/browser/browser_task_traits.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_task_traits.h)
390to facilitate posting a task onto a BrowserThread.
391
392Below are some examples of how to specify `TaskTraits`.
fdoraybacba4a22017-05-10 21:10:00393
394```cpp
395// This task has no explicit TaskTraits. It cannot block. Its priority
396// is inherited from the calling context (e.g. if it is posted from
Gabriel Charette141a442582018-07-27 21:23:25397// a BEST_EFFORT task, it will have a BEST_EFFORT priority). It will either
fdoraybacba4a22017-05-10 21:10:00398// block shutdown or be skipped on shutdown.
399base::PostTask(FROM_HERE, base::BindOnce(...));
400
401// This task has the highest priority. The task scheduler will try to
Gabriel Charette141a442582018-07-27 21:23:25402// run it before USER_VISIBLE and BEST_EFFORT tasks.
fdoraybacba4a22017-05-10 21:10:00403base::PostTaskWithTraits(
404 FROM_HERE, {base::TaskPriority::USER_BLOCKING},
405 base::BindOnce(...));
406
407// This task has the lowest priority and is allowed to block (e.g. it
408// can read a file from disk).
409base::PostTaskWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00410 FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
fdoraybacba4a22017-05-10 21:10:00411 base::BindOnce(...));
412
413// This task blocks shutdown. The process won't exit before its
414// execution is complete.
415base::PostTaskWithTraits(
416 FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
417 base::BindOnce(...));
Eric Seckler6cf08db82018-08-30 12:01:55418
419// This task will run on the Browser UI thread.
420base::PostTaskWithTraits(
421 FROM_HERE, {content::BrowserThread::UI},
422 base::BindOnce(...));
fdoraybacba4a22017-05-10 21:10:00423```
424
425## Keeping the Browser Responsive
426
427Do not perform expensive work on the main thread, the IO thread or any sequence
428that is expected to run tasks with a low latency. Instead, perform expensive
429work asynchronously using `base::PostTaskAndReply*()` or
Gabriel Charette90480312018-02-16 15:10:05430`SequencedTaskRunner::PostTaskAndReply()`. Note that asynchronous/overlapped
431I/O on the IO thread are fine.
fdoraybacba4a22017-05-10 21:10:00432
433Example: Running the code below on the main thread will prevent the browser from
434responding to user input for a long time.
435
436```cpp
437// GetHistoryItemsFromDisk() may block for a long time.
438// AddHistoryItemsToOmniboxDropDown() updates the UI and therefore must
439// be called on the main thread.
440AddHistoryItemsToOmniboxDropdown(GetHistoryItemsFromDisk("keyword"));
441```
442
443The code below solves the problem by scheduling a call to
444`GetHistoryItemsFromDisk()` in a thread pool followed by a call to
445`AddHistoryItemsToOmniboxDropdown()` on the origin sequence (the main thread in
446this case). The return value of the first call is automatically provided as
447argument to the second call.
448
449```cpp
450base::PostTaskWithTraitsAndReplyWithResult(
451 FROM_HERE, {base::MayBlock()},
452 base::BindOnce(&GetHistoryItemsFromDisk, "keyword"),
453 base::BindOnce(&AddHistoryItemsToOmniboxDropdown));
454```
455
456## Posting a Task with a Delay
457
458### Posting a One-Off Task with a Delay
459
460To post a task that must run once after a delay expires, use
461`base::PostDelayedTask*()` or `TaskRunner::PostDelayedTask()`.
462
463```cpp
464base::PostDelayedTaskWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00465 FROM_HERE, {base::TaskPriority::BEST_EFFORT}, base::BindOnce(&Task),
fdoraybacba4a22017-05-10 21:10:00466 base::TimeDelta::FromHours(1));
467
468scoped_refptr<base::SequencedTaskRunner> task_runner =
Gabriel Charetteb10aeeb2018-07-26 20:15:00469 base::CreateSequencedTaskRunnerWithTraits({base::TaskPriority::BEST_EFFORT});
fdoraybacba4a22017-05-10 21:10:00470task_runner->PostDelayedTask(
471 FROM_HERE, base::BindOnce(&Task), base::TimeDelta::FromHours(1));
472```
473
474*** note
475**NOTE:** A task that has a 1-hour delay probably doesn’t have to run right away
Gabriel Charetteb10aeeb2018-07-26 20:15:00476when its delay expires. Specify `base::TaskPriority::BEST_EFFORT` to prevent it
fdoraybacba4a22017-05-10 21:10:00477from slowing down the browser when its delay expires.
478***
479
480### Posting a Repeating Task with a Delay
481To post a task that must run at regular intervals,
482use [`base::RepeatingTimer`](https://cs.chromium.org/chromium/src/base/timer/timer.h).
483
484```cpp
485class A {
486 public:
487 ~A() {
488 // The timer is stopped automatically when it is deleted.
489 }
490 void StartDoingStuff() {
491 timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1),
492 this, &MyClass::DoStuff);
493 }
494 void StopDoingStuff() {
495 timer_.Stop();
496 }
497 private:
498 void DoStuff() {
499 // This method is called every second on the sequence that invoked
500 // StartDoingStuff().
501 }
502 base::RepeatingTimer timer_;
503};
504```
505
506## Cancelling a Task
507
508### Using base::WeakPtr
509
510[`base::WeakPtr`](https://cs.chromium.org/chromium/src/base/memory/weak_ptr.h)
511can be used to ensure that any callback bound to an object is canceled when that
512object is destroyed.
513
514```cpp
515int Compute() { … }
516
517class A {
518 public:
519 A() : weak_ptr_factory_(this) {}
520
521 void ComputeAndStore() {
522 // Schedule a call to Compute() in a thread pool followed by
523 // a call to A::Store() on the current sequence. The call to
524 // A::Store() is canceled when |weak_ptr_factory_| is destroyed.
525 // (guarantees that |this| will not be used-after-free).
526 base::PostTaskAndReplyWithResult(
527 FROM_HERE, base::BindOnce(&Compute),
528 base::BindOnce(&A::Store, weak_ptr_factory_.GetWeakPtr()));
529 }
530
531 private:
532 void Store(int value) { value_ = value; }
533
534 int value_;
535 base::WeakPtrFactory<A> weak_ptr_factory_;
536};
537```
538
539Note: `WeakPtr` is not thread-safe: `GetWeakPtr()`, `~WeakPtrFactory()`, and
540`Compute()` (bound to a `WeakPtr`) must all run on the same sequence.
541
542### Using base::CancelableTaskTracker
543
544[`base::CancelableTaskTracker`](https://cs.chromium.org/chromium/src/base/task/cancelable_task_tracker.h)
545allows cancellation to happen on a different sequence than the one on which
546tasks run. Keep in mind that `CancelableTaskTracker` cannot cancel tasks that
547have already started to run.
548
549```cpp
550auto task_runner = base::CreateTaskRunnerWithTraits(base::TaskTraits());
551base::CancelableTaskTracker cancelable_task_tracker;
552cancelable_task_tracker.PostTask(task_runner.get(), FROM_HERE,
Peter Kasting341e1fb2018-02-24 00:03:01553 base::DoNothing());
fdoraybacba4a22017-05-10 21:10:00554// Cancels Task(), only if it hasn't already started running.
555cancelable_task_tracker.TryCancelAll();
556```
557
558## Testing
559
560To test code that uses `base::ThreadTaskRunnerHandle`,
561`base::SequencedTaskRunnerHandle` or a function in
Gabriel Charette04b138f2018-08-06 00:03:22562[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h), instantiate a
fdoraybacba4a22017-05-10 21:10:00563[`base::test::ScopedTaskEnvironment`](https://cs.chromium.org/chromium/src/base/test/scoped_task_environment.h)
564for the scope of the test.
565
566```cpp
567class MyTest : public testing::Test {
568 public:
569 // ...
570 protected:
571 base::test::ScopedTaskEnvironment scoped_task_environment_;
572};
573
574TEST(MyTest, MyTest) {
575 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&A));
576 base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
577 base::BindOnce(&B));
578 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
579 FROM_HERE, base::BindOnce(&C), base::TimeDelta::Max());
580
581 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until it is empty.
582 // Delayed tasks are not added to the queue until they are ripe for execution.
583 base::RunLoop().RunUntilIdle();
584 // A and B have been executed. C is not ripe for execution yet.
585
586 base::RunLoop run_loop;
587 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&D));
588 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure());
589 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&E));
590
591 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until QuitClosure is
592 // invoked.
593 run_loop.Run();
594 // D and run_loop.QuitClosure() have been executed. E is still in the queue.
595
596 // Tasks posted to task scheduler run asynchronously as they are posted.
597 base::PostTaskWithTraits(FROM_HERE, base::TaskTraits(), base::BindOnce(&F));
598 auto task_runner =
599 base::CreateSequencedTaskRunnerWithTraits(base::TaskTraits());
600 task_runner->PostTask(FROM_HERE, base::BindOnce(&G));
601
602 // To block until all tasks posted to task scheduler are done running:
603 base::TaskScheduler::GetInstance()->FlushForTesting();
604 // F and G have been executed.
605
606 base::PostTaskWithTraitsAndReplyWithResult(
607 FROM_HERE, base::TaskTrait(),
608 base::BindOnce(&H), base::BindOnce(&I));
609
610 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until both the
611 // (Thread|Sequenced)TaskRunnerHandle queue and the TaskSchedule queue are
612 // empty:
613 scoped_task_environment_.RunUntilIdle();
614 // E, H, I have been executed.
615}
616```
617
fdoraybacba4a22017-05-10 21:10:00618## Using TaskScheduler in a New Process
619
620TaskScheduler needs to be initialized in a process before the functions in
Gabriel Charette04b138f2018-08-06 00:03:22621[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h)
fdoraybacba4a22017-05-10 21:10:00622can be used. Initialization of TaskScheduler in the Chrome browser process and
623child processes (renderer, GPU, utility) has already been taken care of. To use
624TaskScheduler in another process, initialize TaskScheduler early in the main
625function:
626
627```cpp
628// This initializes and starts TaskScheduler with default params.
629base::TaskScheduler::CreateAndStartWithDefaultParams(“process_name”);
Gabriel Charette04b138f2018-08-06 00:03:22630// The base/task/post_task.h API can now be used. Tasks will be // scheduled as
631// they are posted.
fdoraybacba4a22017-05-10 21:10:00632
633// This initializes TaskScheduler.
634base::TaskScheduler::Create(“process_name”);
Gabriel Charette04b138f2018-08-06 00:03:22635// The base/task/post_task.h API can now be used. No threads // will be created
636// and no tasks will be scheduled until after Start() is called.
fdoraybacba4a22017-05-10 21:10:00637base::TaskScheduler::GetInstance()->Start(params);
638// TaskScheduler can now create threads and schedule tasks.
639```
640
641And shutdown TaskScheduler late in the main function:
642
643```cpp
644base::TaskScheduler::GetInstance()->Shutdown();
645// Tasks posted with TaskShutdownBehavior::BLOCK_SHUTDOWN and
646// tasks posted with TaskShutdownBehavior::SKIP_ON_SHUTDOWN that
647// have started to run before the Shutdown() call have now completed their
648// execution. Tasks posted with
649// TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN may still be
650// running.
651```
Gabriel Charetteb86e5fe62017-06-08 19:39:28652## TaskRunner ownership (encourage no dependency injection)
Sebastien Marchandc95489b2017-05-25 16:39:34653
654TaskRunners shouldn't be passed through several components. Instead, the
655components that uses a TaskRunner should be the one that creates it.
656
657See [this example](https://codereview.chromium.org/2885173002/) of a
658refactoring where a TaskRunner was passed through a lot of components only to be
659used in an eventual leaf. The leaf can and should now obtain its TaskRunner
660directly from
Gabriel Charette04b138f2018-08-06 00:03:22661[`base/task/post_task.h`](https://cs.chromium.org/chromium/src/base/task/post_task.h).
Gabriel Charetteb86e5fe62017-06-08 19:39:28662
663Dependency injection of TaskRunners can still seldomly be useful to unit test a
664component when triggering a specific race in a specific way is essential to the
665test. For such cases the preferred approach is the following:
666
667```cpp
668class FooWithCustomizableTaskRunnerForTesting {
669 public:
670
671 void SetBackgroundTaskRunnerForTesting(
michaelpg12c04572017-06-26 23:25:06672 scoped_refptr<base::SequencedTaskRunner> background_task_runner);
Gabriel Charetteb86e5fe62017-06-08 19:39:28673
674 private:
michaelpg12c04572017-06-26 23:25:06675 scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
676 base::CreateSequencedTaskRunnerWithTraits(
Gabriel Charetteb10aeeb2018-07-26 20:15:00677 {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
Gabriel Charetteb86e5fe62017-06-08 19:39:28678}
679```
680
681Note that this still allows removing all layers of plumbing between //chrome and
682that component since unit tests will use the leaf layer directly.
Gabriel Charette8917f4c2018-11-22 15:50:28683
684## FAQ
685See [Threading and Tasks FAQ](threading_and_tasks_faq.md) for more examples.