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