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