blob: 280f1f254707d7a750489bd07fcf86aca414ca85 [file] [log] [blame] [view]
fdoraybacba4a22017-05-10 21:10:001# Threading and Tasks in Chrome
2
3[TOC]
4
5## Overview
6
7### Threads
8
9Every Chrome process has
10
11* a main thread
12 * in the browser process: updates the UI
13 * in renderer processes: runs most of Blink
14* an IO thread
15 * in the browser process: handles IPCs and network requests
16 * in renderer processes: handles IPCs
17* a few more special-purpose threads
18* and a pool of general-purpose threads
19
20Most threads have a loop that gets tasks from a queue and runs them (the queue
21may be shared between multiple threads).
22
23### Tasks
24
25A task is a `base::OnceClosure` added to a queue for asynchronous execution.
26
27A `base::OnceClosure` stores a function pointer and arguments. It has a `Run()`
28method that invokes the function pointer using the bound arguments. It is
29created using `base::BindOnce`. (ref. [Callback<> and Bind()
30documentation](callback.md)).
31
32```
33void TaskA() {}
34void TaskB(int v) {}
35
36auto task_a = base::BindOnce(&TaskA);
37auto task_b = base::BindOnce(&TaskB, 42);
38```
39
40A group of tasks can be executed in one of the following ways:
41
42* [Parallel](#Posting-a-Parallel-Task): No task execution ordering, possibly all
43 at once on any thread
44* [Sequenced](#Posting-a-Sequenced-Task): Tasks executed in posting order, one
45 at a time on any thread.
46* [Single Threaded](#Posting-Multiple-Tasks-to-the-Same-Thread): Tasks executed
47 in posting order, one at a time on a single thread.
48 * [COM Single Threaded](#Posting-Tasks-to-a-COM-Single-Thread-Apartment-STA_Thread-Windows_):
49 A variant of single threaded with COM initialized.
50
gab2a4576052017-06-07 23:36:1251### Prefer Sequences to Threads
52
Gabriel Charetteb86e5fe62017-06-08 19:39:2853**Sequenced execution mode is far preferred to Single Threaded** in scenarios
gab2a4576052017-06-07 23:36:1254that require mere thread-safety as it opens up scheduling paradigms that
55wouldn't be possible otherwise (sequences can hop threads instead of being stuck
56behind unrelated work on a dedicated thread). Ability to hop threads also means
57the thread count can dynamically adapt to the machine's true resource
58availability (faster on bigger machines, avoids trashing on slower machines).
59
60Many core APIs were recently made sequence-friendly (classes are rarely
61thread-affine -- i.e. only when using thread-local-storage or third-party APIs
62that do). But the codebase has long evolved assuming single-threaded contexts...
63If your class could run on a sequence but is blocked by an overzealous use of
64ThreadChecker/ThreadTaskRunnerHandle/SingleThreadTaskRunner in a leaf
65dependency, consider fixing that dependency for everyone's benefit (or at the
66very least file a blocking bug against https://crbug.com/675631 and flag your
67use of base::CreateSingleThreadTaskRunnerWithTraits() with a TODO against your
68bug to use base::CreateSequencedTaskRunnerWithTraits() when fixed).
69
Gabriel Charette01567ac2017-06-09 15:31:1070Detailed documentation on how to migrate from single-threaded contexts to
71sequenced contexts can be found [here](task_scheduler_migration.md).
72
gab2a4576052017-06-07 23:36:1273The discussion below covers all of these ways to execute tasks in details.
fdoraybacba4a22017-05-10 21:10:0074
75## Posting a Parallel Task
76
77### Direct Posting to the Task Scheduler
78
79A task that can run on any thread and doesn’t have ordering or mutual exclusion
80requirements with other tasks should be posted using one of the
81`base::PostTask*()` functions defined in
82[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h).
83
84```cpp
85base::PostTask(FROM_HERE, base::BindOnce(&Task));
86```
87
88This posts tasks with default traits.
89
90The `base::PostTask*WithTraits()` functions allow the caller to provide
91additional details about the task via TaskTraits (ref.
92[Annotating Tasks with TaskTraits](#Annotating-Tasks-with-TaskTraits)).
93
94```cpp
95base::PostTaskWithTraits(
96 FROM_HERE, {base::TaskPriority::BACKGROUND, MayBlock()},
97 base::BindOnce(&Task));
98```
99
fdoray52bf5552017-05-11 12:43:59100### Posting via a TaskRunner
fdoraybacba4a22017-05-10 21:10:00101
102A parallel
103[`TaskRunner`](https://cs.chromium.org/chromium/src/base/task_runner.h) is an
104alternative to calling `base::PostTask*()` directly. This is mainly useful when
105it isn’t known in advance whether tasks will be posted in parallel, in sequence,
fdoray52bf5552017-05-11 12:43:59106or to a single-thread (ref.
107[Posting a Sequenced Task](#Posting-a-Sequenced-Task),
108[Posting Multiple Tasks to the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread)).
109Since `TaskRunner` is the base class of `SequencedTaskRunner` and
110`SingleThreadTaskRunner`, a `scoped_refptr<TaskRunner>` member can hold a
fdoraybacba4a22017-05-10 21:10:00111`TaskRunner`, a `SequencedTaskRunner` or a `SingleThreadTaskRunner`.
112
113```cpp
114class A {
115 public:
116 A() = default;
117
118 void set_task_runner_for_testing(
119 scoped_refptr<base::TaskRunner> task_runner) {
120 task_runner_ = std::move(task_runner);
121 }
122
123 void DoSomething() {
124 // In production, A is always posted in parallel. In test, it is posted to
125 // the TaskRunner provided via set_task_runner_for_testing().
126 task_runner_->PostTask(FROM_HERE, base::BindOnce(&A));
127 }
128
129 private:
130 scoped_refptr<base::TaskRunner> task_runner_ =
131 base::CreateTaskRunnerWithTraits({base::TaskPriority::USER_VISIBLE});
132};
133```
134
135Unless a test needs to control precisely how tasks are executed, it is preferred
136to call `base::PostTask*()` directly (ref. [Testing](#Testing) for less invasive
137ways of controlling tasks in tests).
138
139## Posting a Sequenced Task
140
141A sequence is a set of tasks that run one at a time in posting order (not
142necessarily on the same thread). To post tasks as part of a sequence, use a
143 [`SequencedTaskRunner`](https://cs.chromium.org/chromium/src/base/sequenced_task_runner.h).
144
145### Posting to a New Sequence
146
147A `SequencedTaskRunner` can be created by
148`base::CreateSequencedTaskRunnerWithTraits()`.
149
150```cpp
151scoped_refptr<SequencedTaskRunner> sequenced_task_runner =
152 base::CreateSequencedTaskRunnerWithTraits(...);
153
154// TaskB runs after TaskA completes.
155sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA));
156sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB));
157```
158
159### Posting to the Current Sequence
160
161The `SequencedTaskRunner` to which the current task was posted can be obtained
162via
163[`SequencedTaskRunnerHandle::Get()`](https://cs.chromium.org/chromium/src/base/threading/sequenced_task_runner_handle.h).
164
165*** note
166**NOTE:** it is invalid to call `SequencedTaskRunnerHandle::Get()` from a
167parallel task, but it is valid from a single-threaded task (a
168`SingleThreadTaskRunner` is a `SequencedTaskRunner`).
169***
170
171```cpp
172// The task will run after any task that has already been posted
173// to the SequencedTaskRunner to which the current task was posted
174// (in particular, it will run after the current task completes).
175// It is also guaranteed that it won’t run concurrently with any
176// task posted to that SequencedTaskRunner.
177base::SequencedTaskRunnerHandle::Get()->
178 PostTask(FROM_HERE, base::BindOnce(&Task));
179```
180
181## Using Sequences Instead of Locks
182
183Usage of locks is discouraged in Chrome. Sequences inherently provide
184thread-safety. Prefer classes that are always accessed from the same sequence to
185managing your own thread-safety with locks.
186
187```cpp
188class A {
189 public:
190 A() {
191 // Do not require accesses to be on the creation sequence.
isherman8c33b8a2017-06-27 19:18:30192 DETACH_FROM_SEQUENCE(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00193 }
194
195 void AddValue(int v) {
196 // Check that all accesses are on the same sequence.
isherman8c33b8a2017-06-27 19:18:30197 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00198 values_.push_back(v);
199}
200
201 private:
isherman8c33b8a2017-06-27 19:18:30202 SEQUENCE_CHECKER(sequence_checker_);
fdoraybacba4a22017-05-10 21:10:00203
204 // No lock required, because all accesses are on the
205 // same sequence.
206 std::vector<int> values_;
207};
208
209A a;
210scoped_refptr<SequencedTaskRunner> task_runner_for_a = ...;
211task_runner->PostTask(FROM_HERE,
212 base::BindOnce(&A::AddValue, base::Unretained(&a)));
213task_runner->PostTask(FROM_HERE,
214 base::BindOnce(&A::AddValue, base::Unretained(&a)));
215
216// Access from a different sequence causes a DCHECK failure.
217scoped_refptr<SequencedTaskRunner> other_task_runner = ...;
218other_task_runner->PostTask(FROM_HERE,
219 base::BindOnce(&A::AddValue, base::Unretained(&a)));
220```
221
222## Posting Multiple Tasks to the Same Thread
223
224If multiple tasks need to run on the same thread, post them to a
225[`SingleThreadTaskRunner`](https://cs.chromium.org/chromium/src/base/single_thread_task_runner.h).
226All tasks posted to the same `SingleThreadTaskRunner` run on the same thread in
227posting order.
228
229### Posting to the Main Thread or to the IO Thread in the Browser Process
230
231To post tasks to the main thread or to the IO thread, get the appropriate
232SingleThreadTaskRunner using `content::BrowserThread::GetTaskRunnerForThread`.
233
234```cpp
235content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
236 ->PostTask(FROM_HERE, ...);
237
238content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
239 ->PostTask(FROM_HERE, ...);
240```
241
242The main thread and the IO thread are already super busy. Therefore, prefer
fdoray52bf5552017-05-11 12:43:59243posting to a general purpose thread when possible (ref.
244[Posting a Parallel Task](#Posting-a-Parallel-Task),
245[Posting a Sequenced task](#Posting-a-Sequenced-Task)).
246Good reasons to post to the main thread are to update the UI or access objects
247that are bound to it (e.g. `Profile`). A good reason to post to the IO thread is
248to access the internals of components that are bound to it (e.g. IPCs, network).
249Note: It is not necessary to have an explicit post task to the IO thread to
250send/receive an IPC or send/receive data on the network.
fdoraybacba4a22017-05-10 21:10:00251
252### Posting to the Main Thread in a Renderer Process
253TODO
254
255### Posting to a Custom SingleThreadTaskRunner
256
257If multiple tasks need to run on the same thread and that thread doesn’t have to
258be the main thread or the IO thread, post them to a `SingleThreadTaskRunner`
259created by `base::CreateSingleThreadTaskRunnerWithTraits`.
260
261```cpp
262scoped_refptr<SequencedTaskRunner> single_thread_task_runner =
263 base::CreateSingleThreadTaskRunnerWithTraits(...);
264
265// TaskB runs after TaskA completes. Both tasks run on the same thread.
266single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA));
267single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB));
268```
269
270*** note
271**IMPORTANT:** You should rarely need this, most classes in Chromium require
272thread-safety (which sequences provide) not thread-affinity. If an API you’re
273using is incorrectly thread-affine (i.e. using
274[`base::ThreadChecker`](https://cs.chromium.org/chromium/src/base/threading/thread_checker.h)
275when it’s merely thread-unsafe and should use
276[`base::SequenceChecker`](https://cs.chromium.org/chromium/src/base/sequence_checker.h)),
277please consider fixing it instead of making things worse by also making your API thread-affine.
278***
279
280### Posting to the Current Thread
281
282*** note
283**IMPORTANT:** To post a task that needs mutual exclusion with the current
284sequence of tasks but doesn’t absolutely need to run on the current thread, use
285`SequencedTaskRunnerHandle::Get()` instead of `ThreadTaskRunnerHandle::Get()`
286(ref. [Posting to the Current Sequence](#Posting-to-the-Current-Sequence)). That
287will better document the requirements of the posted task. In a single-thread
288task, `SequencedTaskRunnerHandle::Get()` is equivalent to
289`ThreadTaskRunnerHandle::Get()`.
290***
291
292To post a task to the current thread, use [`ThreadTaskRunnerHandle`](https://cs.chromium.org/chromium/src/base/threading/thread_task_runner_handle.h).
293
294```cpp
295// The task will run on the current thread in the future.
296base::ThreadTaskRunnerHandle::Get()->PostTask(
297 FROM_HERE, base::BindOnce(&Task));
298```
299
300*** note
301**NOTE:** It is invalid to call `ThreadTaskRunnerHandle::Get()` from a parallel
302or a sequenced task.
303***
304
305## Posting Tasks to a COM Single-Thread Apartment (STA) Thread (Windows)
306
307Tasks that need to run on a COM Single-Thread Apartment (STA) thread must be
308posted to a `SingleThreadTaskRunner` returned by
309`CreateCOMSTATaskRunnerWithTraits()`. As mentioned in [Posting Multiple Tasks to
310the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread), all tasks posted
311to the same `SingleThreadTaskRunner` run on the same thread in posting order.
312
313```cpp
314// Task(A|B|C)UsingCOMSTA will run on the same COM STA thread.
315
316void TaskAUsingCOMSTA() {
317 // [ This runs on a COM STA thread. ]
318
319 // Make COM STA calls.
320 // ...
321
322 // Post another task to the current COM STA thread.
323 base::ThreadTaskRunnerHandle::Get()->PostTask(
324 FROM_HERE, base::BindOnce(&TaskCUsingCOMSTA));
325}
326void TaskBUsingCOMSTA() { }
327void TaskCUsingCOMSTA() { }
328
329auto com_sta_task_runner = base::CreateCOMSTATaskRunnerWithTraits(...);
330com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskAUsingCOMSTA));
331com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskBUsingCOMSTA));
332```
333
334## Annotating Tasks with TaskTraits
335
336[`TaskTraits`](https://cs.chromium.org/chromium/src/base/task_scheduler/task_traits.h)
337encapsulate information about a task that helps the task scheduler make better
338scheduling decisions.
339
340All `PostTask*()` functions in
341[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h)
342have an overload that takes `TaskTraits` as argument and one that doesn’t. The
343overload that doesn’t take `TaskTraits` as argument is appropriate for tasks
344that:
345- Don’t block (ref. MayBlock and WithBaseSyncPrimitives).
346- Prefer inheriting the current priority to specifying their own.
347- Can either block shutdown or be skipped on shutdown (task scheduler is free to choose a fitting default).
348Tasks that don’t match this description must be posted with explicit TaskTraits.
349
350[`base/task_scheduler/task_traits.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/task_traits.h)
351provides exhaustive documentation of available traits. Below are some examples
352of how to specify `TaskTraits`.
353
354```cpp
355// This task has no explicit TaskTraits. It cannot block. Its priority
356// is inherited from the calling context (e.g. if it is posted from
357// a BACKGROUND task, it will have a BACKGROUND priority). It will either
358// block shutdown or be skipped on shutdown.
359base::PostTask(FROM_HERE, base::BindOnce(...));
360
361// This task has the highest priority. The task scheduler will try to
362// run it before USER_VISIBLE and BACKGROUND tasks.
363base::PostTaskWithTraits(
364 FROM_HERE, {base::TaskPriority::USER_BLOCKING},
365 base::BindOnce(...));
366
367// This task has the lowest priority and is allowed to block (e.g. it
368// can read a file from disk).
369base::PostTaskWithTraits(
370 FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
371 base::BindOnce(...));
372
373// This task blocks shutdown. The process won't exit before its
374// execution is complete.
375base::PostTaskWithTraits(
376 FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
377 base::BindOnce(...));
378```
379
380## Keeping the Browser Responsive
381
382Do not perform expensive work on the main thread, the IO thread or any sequence
383that is expected to run tasks with a low latency. Instead, perform expensive
384work asynchronously using `base::PostTaskAndReply*()` or
385`SequencedTaskRunner::PostTaskAndReply()`.
386
387Example: Running the code below on the main thread will prevent the browser from
388responding to user input for a long time.
389
390```cpp
391// GetHistoryItemsFromDisk() may block for a long time.
392// AddHistoryItemsToOmniboxDropDown() updates the UI and therefore must
393// be called on the main thread.
394AddHistoryItemsToOmniboxDropdown(GetHistoryItemsFromDisk("keyword"));
395```
396
397The code below solves the problem by scheduling a call to
398`GetHistoryItemsFromDisk()` in a thread pool followed by a call to
399`AddHistoryItemsToOmniboxDropdown()` on the origin sequence (the main thread in
400this case). The return value of the first call is automatically provided as
401argument to the second call.
402
403```cpp
404base::PostTaskWithTraitsAndReplyWithResult(
405 FROM_HERE, {base::MayBlock()},
406 base::BindOnce(&GetHistoryItemsFromDisk, "keyword"),
407 base::BindOnce(&AddHistoryItemsToOmniboxDropdown));
408```
409
410## Posting a Task with a Delay
411
412### Posting a One-Off Task with a Delay
413
414To post a task that must run once after a delay expires, use
415`base::PostDelayedTask*()` or `TaskRunner::PostDelayedTask()`.
416
417```cpp
418base::PostDelayedTaskWithTraits(
419 FROM_HERE, {base::TaskPriority::BACKGROUND}, base::BindOnce(&Task),
420 base::TimeDelta::FromHours(1));
421
422scoped_refptr<base::SequencedTaskRunner> task_runner =
423 base::CreateSequencedTaskRunnerWithTraits({base::TaskPriority::BACKGROUND});
424task_runner->PostDelayedTask(
425 FROM_HERE, base::BindOnce(&Task), base::TimeDelta::FromHours(1));
426```
427
428*** note
429**NOTE:** A task that has a 1-hour delay probably doesn’t have to run right away
430when its delay expires. Specify `base::TaskPriority::BACKGROUND` to prevent it
431from slowing down the browser when its delay expires.
432***
433
434### Posting a Repeating Task with a Delay
435To post a task that must run at regular intervals,
436use [`base::RepeatingTimer`](https://cs.chromium.org/chromium/src/base/timer/timer.h).
437
438```cpp
439class A {
440 public:
441 ~A() {
442 // The timer is stopped automatically when it is deleted.
443 }
444 void StartDoingStuff() {
445 timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1),
446 this, &MyClass::DoStuff);
447 }
448 void StopDoingStuff() {
449 timer_.Stop();
450 }
451 private:
452 void DoStuff() {
453 // This method is called every second on the sequence that invoked
454 // StartDoingStuff().
455 }
456 base::RepeatingTimer timer_;
457};
458```
459
460## Cancelling a Task
461
462### Using base::WeakPtr
463
464[`base::WeakPtr`](https://cs.chromium.org/chromium/src/base/memory/weak_ptr.h)
465can be used to ensure that any callback bound to an object is canceled when that
466object is destroyed.
467
468```cpp
469int Compute() { … }
470
471class A {
472 public:
473 A() : weak_ptr_factory_(this) {}
474
475 void ComputeAndStore() {
476 // Schedule a call to Compute() in a thread pool followed by
477 // a call to A::Store() on the current sequence. The call to
478 // A::Store() is canceled when |weak_ptr_factory_| is destroyed.
479 // (guarantees that |this| will not be used-after-free).
480 base::PostTaskAndReplyWithResult(
481 FROM_HERE, base::BindOnce(&Compute),
482 base::BindOnce(&A::Store, weak_ptr_factory_.GetWeakPtr()));
483 }
484
485 private:
486 void Store(int value) { value_ = value; }
487
488 int value_;
489 base::WeakPtrFactory<A> weak_ptr_factory_;
490};
491```
492
493Note: `WeakPtr` is not thread-safe: `GetWeakPtr()`, `~WeakPtrFactory()`, and
494`Compute()` (bound to a `WeakPtr`) must all run on the same sequence.
495
496### Using base::CancelableTaskTracker
497
498[`base::CancelableTaskTracker`](https://cs.chromium.org/chromium/src/base/task/cancelable_task_tracker.h)
499allows cancellation to happen on a different sequence than the one on which
500tasks run. Keep in mind that `CancelableTaskTracker` cannot cancel tasks that
501have already started to run.
502
503```cpp
504auto task_runner = base::CreateTaskRunnerWithTraits(base::TaskTraits());
505base::CancelableTaskTracker cancelable_task_tracker;
506cancelable_task_tracker.PostTask(task_runner.get(), FROM_HERE,
507 base::Bind(&base::DoNothing));
508// Cancels Task(), only if it hasn't already started running.
509cancelable_task_tracker.TryCancelAll();
510```
511
512## Testing
513
514To test code that uses `base::ThreadTaskRunnerHandle`,
515`base::SequencedTaskRunnerHandle` or a function in
516[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h), instantiate a
517[`base::test::ScopedTaskEnvironment`](https://cs.chromium.org/chromium/src/base/test/scoped_task_environment.h)
518for the scope of the test.
519
520```cpp
521class MyTest : public testing::Test {
522 public:
523 // ...
524 protected:
525 base::test::ScopedTaskEnvironment scoped_task_environment_;
526};
527
528TEST(MyTest, MyTest) {
529 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&A));
530 base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
531 base::BindOnce(&B));
532 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
533 FROM_HERE, base::BindOnce(&C), base::TimeDelta::Max());
534
535 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until it is empty.
536 // Delayed tasks are not added to the queue until they are ripe for execution.
537 base::RunLoop().RunUntilIdle();
538 // A and B have been executed. C is not ripe for execution yet.
539
540 base::RunLoop run_loop;
541 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&D));
542 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure());
543 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&E));
544
545 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until QuitClosure is
546 // invoked.
547 run_loop.Run();
548 // D and run_loop.QuitClosure() have been executed. E is still in the queue.
549
550 // Tasks posted to task scheduler run asynchronously as they are posted.
551 base::PostTaskWithTraits(FROM_HERE, base::TaskTraits(), base::BindOnce(&F));
552 auto task_runner =
553 base::CreateSequencedTaskRunnerWithTraits(base::TaskTraits());
554 task_runner->PostTask(FROM_HERE, base::BindOnce(&G));
555
556 // To block until all tasks posted to task scheduler are done running:
557 base::TaskScheduler::GetInstance()->FlushForTesting();
558 // F and G have been executed.
559
560 base::PostTaskWithTraitsAndReplyWithResult(
561 FROM_HERE, base::TaskTrait(),
562 base::BindOnce(&H), base::BindOnce(&I));
563
564 // This runs the (Thread|Sequenced)TaskRunnerHandle queue until both the
565 // (Thread|Sequenced)TaskRunnerHandle queue and the TaskSchedule queue are
566 // empty:
567 scoped_task_environment_.RunUntilIdle();
568 // E, H, I have been executed.
569}
570```
571
572## Legacy Post Task APIs
573
574The Chrome browser process has a few legacy named threads (aka
575“BrowserThreads”). Each of these threads runs a specific type of task (e.g. the
576`FILE` thread handles low priority file operations, the `FILE_USER_BLOCKING`
577thread handles high priority file operations, the `CACHE` thread handles cache
578operations…). Usage of these named threads is now discouraged. New code should
579post tasks to task scheduler via
580[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h)
581instead.
582
583If for some reason you absolutely need to post a task to a legacy named thread
584(e.g. because it needs mutual exclusion with a task running on one of these
585threads), this is how you do it:
586
587```cpp
588content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::[IDENTIFIER])
589 ->PostTask(FROM_HERE, base::BindOnce(&Task));
590```
591
592Where `IDENTIFIER` is one of: `DB`, `FILE`, `FILE_USER_BLOCKING`, `PROCESS_LAUNCHER`, `CACHE`.
593
594The Chrome browser process has a “blocking pool” API:
595
596```cpp
597content::BrowserThread::PostBlockingPoolSequencedTask
598content::BrowserThread::GetBlockingPool
599```
600
601All tasks posted through this API are redirected to
602[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h).
603Therefore, there is no reason to add calls to this API.
604
605## Using TaskScheduler in a New Process
606
607TaskScheduler needs to be initialized in a process before the functions in
608[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h)
609can be used. Initialization of TaskScheduler in the Chrome browser process and
610child processes (renderer, GPU, utility) has already been taken care of. To use
611TaskScheduler in another process, initialize TaskScheduler early in the main
612function:
613
614```cpp
615// This initializes and starts TaskScheduler with default params.
616base::TaskScheduler::CreateAndStartWithDefaultParams(“process_name”);
617// The base/task_scheduler/post_task.h API can now be used. Tasks will be
618// scheduled as they are posted.
619
620// This initializes TaskScheduler.
621base::TaskScheduler::Create(“process_name”);
622// The base/task_scheduler/post_task.h API can now be used. No threads
623// will be created and no tasks will be scheduled until after Start() is called.
624base::TaskScheduler::GetInstance()->Start(params);
625// TaskScheduler can now create threads and schedule tasks.
626```
627
628And shutdown TaskScheduler late in the main function:
629
630```cpp
631base::TaskScheduler::GetInstance()->Shutdown();
632// Tasks posted with TaskShutdownBehavior::BLOCK_SHUTDOWN and
633// tasks posted with TaskShutdownBehavior::SKIP_ON_SHUTDOWN that
634// have started to run before the Shutdown() call have now completed their
635// execution. Tasks posted with
636// TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN may still be
637// running.
638```
Gabriel Charetteb86e5fe62017-06-08 19:39:28639## TaskRunner ownership (encourage no dependency injection)
Sebastien Marchandc95489b2017-05-25 16:39:34640
641TaskRunners shouldn't be passed through several components. Instead, the
642components that uses a TaskRunner should be the one that creates it.
643
644See [this example](https://codereview.chromium.org/2885173002/) of a
645refactoring where a TaskRunner was passed through a lot of components only to be
646used in an eventual leaf. The leaf can and should now obtain its TaskRunner
647directly from
648[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h).
Gabriel Charetteb86e5fe62017-06-08 19:39:28649
650Dependency injection of TaskRunners can still seldomly be useful to unit test a
651component when triggering a specific race in a specific way is essential to the
652test. For such cases the preferred approach is the following:
653
654```cpp
655class FooWithCustomizableTaskRunnerForTesting {
656 public:
657
658 void SetBackgroundTaskRunnerForTesting(
michaelpg12c04572017-06-26 23:25:06659 scoped_refptr<base::SequencedTaskRunner> background_task_runner);
Gabriel Charetteb86e5fe62017-06-08 19:39:28660
661 private:
michaelpg12c04572017-06-26 23:25:06662 scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
663 base::CreateSequencedTaskRunnerWithTraits(
Gabriel Charetteb86e5fe62017-06-08 19:39:28664 {base::MayBlock(), base::TaskPriority::BACKGROUND});
665}
666```
667
668Note that this still allows removing all layers of plumbing between //chrome and
669that component since unit tests will use the leaf layer directly.