Index: docs/threading_and_tasks.md |
diff --git a/docs/threading_and_tasks.md b/docs/threading_and_tasks.md |
new file mode 100644 |
index 0000000000000000000000000000000000000000..986d78118cd6172118cdddd7945a13bba7762534 |
--- /dev/null |
+++ b/docs/threading_and_tasks.md |
@@ -0,0 +1,614 @@ |
+# Threading and Tasks in Chrome |
+ |
+[TOC] |
+ |
+## Overview |
+ |
+### Threads |
+ |
+Every Chrome process has |
+ |
+* a main thread |
+ * in the browser process: updates the UI |
+ * in renderer processes: runs most of Blink |
+* an IO thread |
+ * in the browser process: handles IPCs and network requests |
+ * in renderer processes: handles IPCs |
+* a few more special-purpose threads |
+* and a pool of general-purpose threads |
+ |
+Most threads have a loop that gets tasks from a queue and runs them (the queue |
+may be shared between multiple threads). |
+ |
+### Tasks |
+ |
+A task is a `base::OnceClosure` added to a queue for asynchronous execution. |
+ |
+A `base::OnceClosure` stores a function pointer and arguments. It has a `Run()` |
+method that invokes the function pointer using the bound arguments. It is |
+created using `base::BindOnce`. (ref. [Callback<> and Bind() |
+documentation](callback.md)). |
+ |
+``` |
+void TaskA() {} |
+void TaskB(int v) {} |
+ |
+auto task_a = base::BindOnce(&TaskA); |
+auto task_b = base::BindOnce(&TaskB, 42); |
+``` |
+ |
+A group of tasks can be executed in one of the following ways: |
+ |
+* [Parallel](#Posting-a-Parallel-Task): No task execution ordering, possibly all |
+ at once on any thread |
+* [Sequenced](#Posting-a-Sequenced-Task): Tasks executed in posting order, one |
+ at a time on any thread. |
+* [Single Threaded](#Posting-Multiple-Tasks-to-the-Same-Thread): Tasks executed |
+ in posting order, one at a time on a single thread. |
+ * [COM Single Threaded](#Posting-Tasks-to-a-COM-Single-Thread-Apartment-STA_Thread-Windows_): |
+ A variant of single threaded with COM initialized. |
+ |
+The discussion below covers all of these ways to execute tasks. |
+ |
+## Posting a Parallel Task |
+ |
+### Direct Posting to the Task Scheduler |
+ |
+A task that can run on any thread and doesn’t have ordering or mutual exclusion |
+requirements with other tasks should be posted using one of the |
+`base::PostTask*()` functions defined in |
+[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h). |
+ |
+```cpp |
+base::PostTask(FROM_HERE, base::BindOnce(&Task)); |
+``` |
+ |
+This posts tasks with default traits. |
+ |
+The `base::PostTask*WithTraits()` functions allow the caller to provide |
+additional details about the task via TaskTraits (ref. |
+[Annotating Tasks with TaskTraits](#Annotating-Tasks-with-TaskTraits)). |
+ |
+```cpp |
+base::PostTaskWithTraits( |
+ FROM_HERE, {base::TaskPriority::BACKGROUND, MayBlock()}, |
+ base::BindOnce(&Task)); |
+``` |
+ |
+## Posting via a TaskRunner |
+ |
+A parallel |
+[`TaskRunner`](https://cs.chromium.org/chromium/src/base/task_runner.h) is an |
+alternative to calling `base::PostTask*()` directly. This is mainly useful when |
+it isn’t known in advance whether tasks will be posted in parallel, in sequence, |
+or to a single-thread (ref. [Posting a Sequenced Task](#Posting-a-Sequenced- |
+Task), [Posting Multiple Tasks to the Same Thread](#Posting-Multiple-Tasks-to- |
+the-Same-Thread)). Since `TaskRunner` is the base class of `SequencedTaskRunner` |
+and `SingleThreadTaskRunner`, a `scoped_refptr<TaskRunner>` member can hold a |
+`TaskRunner`, a `SequencedTaskRunner` or a `SingleThreadTaskRunner`. |
+ |
+```cpp |
+class A { |
+ public: |
+ A() = default; |
+ |
+ void set_task_runner_for_testing( |
+ scoped_refptr<base::TaskRunner> task_runner) { |
+ task_runner_ = std::move(task_runner); |
+ } |
+ |
+ void DoSomething() { |
+ // In production, A is always posted in parallel. In test, it is posted to |
+ // the TaskRunner provided via set_task_runner_for_testing(). |
+ task_runner_->PostTask(FROM_HERE, base::BindOnce(&A)); |
+ } |
+ |
+ private: |
+ scoped_refptr<base::TaskRunner> task_runner_ = |
+ base::CreateTaskRunnerWithTraits({base::TaskPriority::USER_VISIBLE}); |
+}; |
+``` |
+ |
+Unless a test needs to control precisely how tasks are executed, it is preferred |
+to call `base::PostTask*()` directly (ref. [Testing](#Testing) for less invasive |
+ways of controlling tasks in tests). |
+ |
+## Posting a Sequenced Task |
+ |
+A sequence is a set of tasks that run one at a time in posting order (not |
+necessarily on the same thread). To post tasks as part of a sequence, use a |
+ [`SequencedTaskRunner`](https://cs.chromium.org/chromium/src/base/sequenced_task_runner.h). |
+ |
+### Posting to a New Sequence |
+ |
+A `SequencedTaskRunner` can be created by |
+`base::CreateSequencedTaskRunnerWithTraits()`. |
+ |
+```cpp |
+scoped_refptr<SequencedTaskRunner> sequenced_task_runner = |
+ base::CreateSequencedTaskRunnerWithTraits(...); |
+ |
+// TaskB runs after TaskA completes. |
+sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA)); |
+sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB)); |
+``` |
+ |
+### Posting to the Current Sequence |
+ |
+The `SequencedTaskRunner` to which the current task was posted can be obtained |
+via |
+[`SequencedTaskRunnerHandle::Get()`](https://cs.chromium.org/chromium/src/base/threading/sequenced_task_runner_handle.h). |
+ |
+*** note |
+**NOTE:** it is invalid to call `SequencedTaskRunnerHandle::Get()` from a |
+parallel task, but it is valid from a single-threaded task (a |
+`SingleThreadTaskRunner` is a `SequencedTaskRunner`). |
+*** |
+ |
+```cpp |
+// The task will run after any task that has already been posted |
+// to the SequencedTaskRunner to which the current task was posted |
+// (in particular, it will run after the current task completes). |
+// It is also guaranteed that it won’t run concurrently with any |
+// task posted to that SequencedTaskRunner. |
+base::SequencedTaskRunnerHandle::Get()-> |
+ PostTask(FROM_HERE, base::BindOnce(&Task)); |
+``` |
+ |
+## Using Sequences Instead of Locks |
+ |
+Usage of locks is discouraged in Chrome. Sequences inherently provide |
+thread-safety. Prefer classes that are always accessed from the same sequence to |
+managing your own thread-safety with locks. |
+ |
+```cpp |
+class A { |
+ public: |
+ A() { |
+ // Do not require accesses to be on the creation sequence. |
+ sequence_checker_.DetachFromSequence(); |
+ } |
+ |
+ void AddValue(int v) { |
+ // Check that all accesses are on the same sequence. |
+ DCHECK(sequence_checker_.CalledOnValidSequence()); |
+ values_.push_back(v); |
+} |
+ |
+ private: |
+ base::SequenceChecker sequence_checker_; |
+ |
+ // No lock required, because all accesses are on the |
+ // same sequence. |
+ std::vector<int> values_; |
+}; |
+ |
+A a; |
+scoped_refptr<SequencedTaskRunner> task_runner_for_a = ...; |
+task_runner->PostTask(FROM_HERE, |
+ base::BindOnce(&A::AddValue, base::Unretained(&a))); |
+task_runner->PostTask(FROM_HERE, |
+ base::BindOnce(&A::AddValue, base::Unretained(&a))); |
+ |
+// Access from a different sequence causes a DCHECK failure. |
+scoped_refptr<SequencedTaskRunner> other_task_runner = ...; |
+other_task_runner->PostTask(FROM_HERE, |
+ base::BindOnce(&A::AddValue, base::Unretained(&a))); |
+``` |
+ |
+## Posting Multiple Tasks to the Same Thread |
+ |
+If multiple tasks need to run on the same thread, post them to a |
+[`SingleThreadTaskRunner`](https://cs.chromium.org/chromium/src/base/single_thread_task_runner.h). |
+All tasks posted to the same `SingleThreadTaskRunner` run on the same thread in |
+posting order. |
+ |
+### Posting to the Main Thread or to the IO Thread in the Browser Process |
+ |
+To post tasks to the main thread or to the IO thread, get the appropriate |
+SingleThreadTaskRunner using `content::BrowserThread::GetTaskRunnerForThread`. |
+ |
+```cpp |
+content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI) |
+ ->PostTask(FROM_HERE, ...); |
+ |
+content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO) |
+ ->PostTask(FROM_HERE, ...); |
+``` |
+ |
+The main thread and the IO thread are already super busy. Therefore, prefer |
+posting to a general purpose thread when possible (ref. [Posting a Parallel |
+Task](#Posting-a-Parallel-Task), [Posting a Sequenced task](#Posting-a |
+-Sequenced-Task)). Good reasons to post to the main thread are to update the UI |
+or access objects that are bound to it (e.g. `Profile`). A good reason to post |
+to the IO thread is to access the internals of components that are bound to it |
+(e.g. IPCs, network). Note: It is not necessary to have an explicit post task to |
+the IO thread to send/receive an IPC or send/receive data on the network. |
+ |
+### Posting to the Main Thread in a Renderer Process |
+TODO |
+ |
+### Posting to a Custom SingleThreadTaskRunner |
+ |
+If multiple tasks need to run on the same thread and that thread doesn’t have to |
+be the main thread or the IO thread, post them to a `SingleThreadTaskRunner` |
+created by `base::CreateSingleThreadTaskRunnerWithTraits`. |
+ |
+```cpp |
+scoped_refptr<SequencedTaskRunner> single_thread_task_runner = |
+ base::CreateSingleThreadTaskRunnerWithTraits(...); |
+ |
+// TaskB runs after TaskA completes. Both tasks run on the same thread. |
+single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA)); |
+single_thread_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB)); |
+``` |
+ |
+*** note |
+**IMPORTANT:** You should rarely need this, most classes in Chromium require |
+thread-safety (which sequences provide) not thread-affinity. If an API you’re |
+using is incorrectly thread-affine (i.e. using |
+[`base::ThreadChecker`](https://cs.chromium.org/chromium/src/base/threading/thread_checker.h) |
+when it’s merely thread-unsafe and should use |
+[`base::SequenceChecker`](https://cs.chromium.org/chromium/src/base/sequence_checker.h)), |
+please consider fixing it instead of making things worse by also making your API thread-affine. |
+*** |
+ |
+### Posting to the Current Thread |
+ |
+*** note |
+**IMPORTANT:** To post a task that needs mutual exclusion with the current |
+sequence of tasks but doesn’t absolutely need to run on the current thread, use |
+`SequencedTaskRunnerHandle::Get()` instead of `ThreadTaskRunnerHandle::Get()` |
+(ref. [Posting to the Current Sequence](#Posting-to-the-Current-Sequence)). That |
+will better document the requirements of the posted task. In a single-thread |
+task, `SequencedTaskRunnerHandle::Get()` is equivalent to |
+`ThreadTaskRunnerHandle::Get()`. |
+*** |
+ |
+To post a task to the current thread, use [`ThreadTaskRunnerHandle`](https://cs.chromium.org/chromium/src/base/threading/thread_task_runner_handle.h). |
+ |
+```cpp |
+// The task will run on the current thread in the future. |
+base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&Task)); |
+``` |
+ |
+*** note |
+**NOTE:** It is invalid to call `ThreadTaskRunnerHandle::Get()` from a parallel |
+or a sequenced task. |
+*** |
+ |
+## Posting Tasks to a COM Single-Thread Apartment (STA) Thread (Windows) |
+ |
+Tasks that need to run on a COM Single-Thread Apartment (STA) thread must be |
+posted to a `SingleThreadTaskRunner` returned by |
+`CreateCOMSTATaskRunnerWithTraits()`. As mentioned in [Posting Multiple Tasks to |
+the Same Thread](#Posting-Multiple-Tasks-to-the-Same-Thread), all tasks posted |
+to the same `SingleThreadTaskRunner` run on the same thread in posting order. |
+ |
+```cpp |
+// Task(A|B|C)UsingCOMSTA will run on the same COM STA thread. |
+ |
+void TaskAUsingCOMSTA() { |
+ // [ This runs on a COM STA thread. ] |
+ |
+ // Make COM STA calls. |
+ // ... |
+ |
+ // Post another task to the current COM STA thread. |
+ base::ThreadTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::BindOnce(&TaskCUsingCOMSTA)); |
+} |
+void TaskBUsingCOMSTA() { } |
+void TaskCUsingCOMSTA() { } |
+ |
+auto com_sta_task_runner = base::CreateCOMSTATaskRunnerWithTraits(...); |
+com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskAUsingCOMSTA)); |
+com_sta_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskBUsingCOMSTA)); |
+``` |
+ |
+## Annotating Tasks with TaskTraits |
+ |
+[`TaskTraits`](https://cs.chromium.org/chromium/src/base/task_scheduler/task_traits.h) |
+encapsulate information about a task that helps the task scheduler make better |
+scheduling decisions. |
+ |
+All `PostTask*()` functions in |
+[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h) |
+have an overload that takes `TaskTraits` as argument and one that doesn’t. The |
+overload that doesn’t take `TaskTraits` as argument is appropriate for tasks |
+that: |
+- Don’t block (ref. MayBlock and WithBaseSyncPrimitives). |
+- Prefer inheriting the current priority to specifying their own. |
+- Can either block shutdown or be skipped on shutdown (task scheduler is free to choose a fitting default). |
+Tasks that don’t match this description must be posted with explicit TaskTraits. |
+ |
+[`base/task_scheduler/task_traits.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/task_traits.h) |
+provides exhaustive documentation of available traits. Below are some examples |
+of how to specify `TaskTraits`. |
+ |
+```cpp |
+// This task has no explicit TaskTraits. It cannot block. Its priority |
+// is inherited from the calling context (e.g. if it is posted from |
+// a BACKGROUND task, it will have a BACKGROUND priority). It will either |
+// block shutdown or be skipped on shutdown. |
+base::PostTask(FROM_HERE, base::BindOnce(...)); |
+ |
+// This task has the highest priority. The task scheduler will try to |
+// run it before USER_VISIBLE and BACKGROUND tasks. |
+base::PostTaskWithTraits( |
+ FROM_HERE, {base::TaskPriority::USER_BLOCKING}, |
+ base::BindOnce(...)); |
+ |
+// This task has the lowest priority and is allowed to block (e.g. it |
+// can read a file from disk). |
+base::PostTaskWithTraits( |
+ FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()}, |
+ base::BindOnce(...)); |
+ |
+// This task blocks shutdown. The process won't exit before its |
+// execution is complete. |
+base::PostTaskWithTraits( |
+ FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, |
+ base::BindOnce(...)); |
+``` |
+ |
+## Keeping the Browser Responsive |
+ |
+Do not perform expensive work on the main thread, the IO thread or any sequence |
+that is expected to run tasks with a low latency. Instead, perform expensive |
+work asynchronously using `base::PostTaskAndReply*()` or |
+`SequencedTaskRunner::PostTaskAndReply()`. |
+ |
+Example: Running the code below on the main thread will prevent the browser from |
+responding to user input for a long time. |
+ |
+```cpp |
+// GetHistoryItemsFromDisk() may block for a long time. |
+// AddHistoryItemsToOmniboxDropDown() updates the UI and therefore must |
+// be called on the main thread. |
+AddHistoryItemsToOmniboxDropdown(GetHistoryItemsFromDisk("keyword")); |
+``` |
+ |
+The code below solves the problem by scheduling a call to |
+`GetHistoryItemsFromDisk()` in a thread pool followed by a call to |
+`AddHistoryItemsToOmniboxDropdown()` on the origin sequence (the main thread in |
+this case). The return value of the first call is automatically provided as |
+argument to the second call. |
+ |
+```cpp |
+base::PostTaskWithTraitsAndReplyWithResult( |
+ FROM_HERE, {base::MayBlock()}, |
+ base::BindOnce(&GetHistoryItemsFromDisk, "keyword"), |
+ base::BindOnce(&AddHistoryItemsToOmniboxDropdown)); |
+``` |
+ |
+## Posting a Task with a Delay |
+ |
+### Posting a One-Off Task with a Delay |
+ |
+To post a task that must run once after a delay expires, use |
+`base::PostDelayedTask*()` or `TaskRunner::PostDelayedTask()`. |
+ |
+```cpp |
+base::PostDelayedTaskWithTraits( |
+ FROM_HERE, {base::TaskPriority::BACKGROUND}, base::BindOnce(&Task), |
+ base::TimeDelta::FromHours(1)); |
+ |
+scoped_refptr<base::SequencedTaskRunner> task_runner = |
+ base::CreateSequencedTaskRunnerWithTraits({base::TaskPriority::BACKGROUND}); |
+task_runner->PostDelayedTask( |
+ FROM_HERE, base::BindOnce(&Task), base::TimeDelta::FromHours(1)); |
+``` |
+ |
+*** note |
+**NOTE:** A task that has a 1-hour delay probably doesn’t have to run right away |
+when its delay expires. Specify `base::TaskPriority::BACKGROUND` to prevent it |
+from slowing down the browser when its delay expires. |
+*** |
+ |
+### Posting a Repeating Task with a Delay |
+To post a task that must run at regular intervals, |
+use [`base::RepeatingTimer`](https://cs.chromium.org/chromium/src/base/timer/timer.h). |
+ |
+```cpp |
+class A { |
+ public: |
+ ~A() { |
+ // The timer is stopped automatically when it is deleted. |
+ } |
+ void StartDoingStuff() { |
+ timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1), |
+ this, &MyClass::DoStuff); |
+ } |
+ void StopDoingStuff() { |
+ timer_.Stop(); |
+ } |
+ private: |
+ void DoStuff() { |
+ // This method is called every second on the sequence that invoked |
+ // StartDoingStuff(). |
+ } |
+ base::RepeatingTimer timer_; |
+}; |
+``` |
+ |
+## Cancelling a Task |
+ |
+### Using base::WeakPtr |
+ |
+[`base::WeakPtr`](https://cs.chromium.org/chromium/src/base/memory/weak_ptr.h) |
+can be used to ensure that any callback bound to an object is canceled when that |
+object is destroyed. |
+ |
+```cpp |
+int Compute() { … } |
+ |
+class A { |
+ public: |
+ A() : weak_ptr_factory_(this) {} |
+ |
+ void ComputeAndStore() { |
+ // Schedule a call to Compute() in a thread pool followed by |
+ // a call to A::Store() on the current sequence. The call to |
+ // A::Store() is canceled when |weak_ptr_factory_| is destroyed. |
+ // (guarantees that |this| will not be used-after-free). |
+ base::PostTaskAndReplyWithResult( |
+ FROM_HERE, base::BindOnce(&Compute), |
+ base::BindOnce(&A::Store, weak_ptr_factory_.GetWeakPtr())); |
+ } |
+ |
+ private: |
+ void Store(int value) { value_ = value; } |
+ |
+ int value_; |
+ base::WeakPtrFactory<A> weak_ptr_factory_; |
+}; |
+``` |
+ |
+Note: `WeakPtr` is not thread-safe: `GetWeakPtr()`, `~WeakPtrFactory()`, and |
+`Compute()` (bound to a `WeakPtr`) must all run on the same sequence. |
+ |
+### Using base::CancelableTaskTracker |
+ |
+[`base::CancelableTaskTracker`](https://cs.chromium.org/chromium/src/base/task/cancelable_task_tracker.h) |
+allows cancellation to happen on a different sequence than the one on which |
+tasks run. Keep in mind that `CancelableTaskTracker` cannot cancel tasks that |
+have already started to run. |
+ |
+```cpp |
+auto task_runner = base::CreateTaskRunnerWithTraits(base::TaskTraits()); |
+base::CancelableTaskTracker cancelable_task_tracker; |
+cancelable_task_tracker.PostTask(task_runner.get(), FROM_HERE, |
+ base::Bind(&base::DoNothing)); |
+// Cancels Task(), only if it hasn't already started running. |
+cancelable_task_tracker.TryCancelAll(); |
+``` |
+ |
+## Testing |
+ |
+To test code that uses `base::ThreadTaskRunnerHandle`, |
+`base::SequencedTaskRunnerHandle` or a function in |
+[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h), instantiate a |
+[`base::test::ScopedTaskEnvironment`](https://cs.chromium.org/chromium/src/base/test/scoped_task_environment.h) |
+for the scope of the test. |
+ |
+```cpp |
+class MyTest : public testing::Test { |
+ public: |
+ // ... |
+ protected: |
+ base::test::ScopedTaskEnvironment scoped_task_environment_; |
+}; |
+ |
+TEST(MyTest, MyTest) { |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&A)); |
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, |
+ base::BindOnce(&B)); |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, base::BindOnce(&C), base::TimeDelta::Max()); |
+ |
+ // This runs the (Thread|Sequenced)TaskRunnerHandle queue until it is empty. |
+ // Delayed tasks are not added to the queue until they are ripe for execution. |
+ base::RunLoop().RunUntilIdle(); |
+ // A and B have been executed. C is not ripe for execution yet. |
+ |
+ base::RunLoop run_loop; |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&D)); |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop.QuitClosure()); |
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::BindOnce(&E)); |
+ |
+ // This runs the (Thread|Sequenced)TaskRunnerHandle queue until QuitClosure is |
+ // invoked. |
+ run_loop.Run(); |
+ // D and run_loop.QuitClosure() have been executed. E is still in the queue. |
+ |
+ // Tasks posted to task scheduler run asynchronously as they are posted. |
+ base::PostTaskWithTraits(FROM_HERE, base::TaskTraits(), base::BindOnce(&F)); |
+ auto task_runner = |
+ base::CreateSequencedTaskRunnerWithTraits(base::TaskTraits()); |
+ task_runner->PostTask(FROM_HERE, base::BindOnce(&G)); |
+ |
+ // To block until all tasks posted to task scheduler are done running: |
+ base::TaskScheduler::GetInstance()->FlushForTesting(); |
+ // F and G have been executed. |
+ |
+ base::PostTaskWithTraitsAndReplyWithResult( |
+ FROM_HERE, base::TaskTrait(), |
+ base::BindOnce(&H), base::BindOnce(&I)); |
+ |
+ // This runs the (Thread|Sequenced)TaskRunnerHandle queue until both the |
+ // (Thread|Sequenced)TaskRunnerHandle queue and the TaskSchedule queue are |
+ // empty: |
+ scoped_task_environment_.RunUntilIdle(); |
+ // E, H, I have been executed. |
+} |
+``` |
+ |
+## Legacy Post Task APIs |
+ |
+The Chrome browser process has a few legacy named threads (aka |
+“BrowserThreads”). Each of these threads runs a specific type of task (e.g. the |
+`FILE` thread handles low priority file operations, the `FILE_USER_BLOCKING` |
+thread handles high priority file operations, the `CACHE` thread handles cache |
+operations…). Usage of these named threads is now discouraged. New code should |
+post tasks to task scheduler via |
+[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h) |
+instead. |
+ |
+If for some reason you absolutely need to post a task to a legacy named thread |
+(e.g. because it needs mutual exclusion with a task running on one of these |
+threads), this is how you do it: |
+ |
+```cpp |
+content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::[IDENTIFIER]) |
+ ->PostTask(FROM_HERE, base::BindOnce(&Task)); |
+``` |
+ |
+Where `IDENTIFIER` is one of: `DB`, `FILE`, `FILE_USER_BLOCKING`, `PROCESS_LAUNCHER`, `CACHE`. |
+ |
+The Chrome browser process has a “blocking pool” API: |
+ |
+```cpp |
+content::BrowserThread::PostBlockingPoolSequencedTask |
+content::BrowserThread::GetBlockingPool |
+``` |
+ |
+All tasks posted through this API are redirected to |
+[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h). |
+Therefore, there is no reason to add calls to this API. |
+ |
+## Using TaskScheduler in a New Process |
+ |
+TaskScheduler needs to be initialized in a process before the functions in |
+[`base/task_scheduler/post_task.h`](https://cs.chromium.org/chromium/src/base/task_scheduler/post_task.h) |
+can be used. Initialization of TaskScheduler in the Chrome browser process and |
+child processes (renderer, GPU, utility) has already been taken care of. To use |
+TaskScheduler in another process, initialize TaskScheduler early in the main |
+function: |
+ |
+```cpp |
+// This initializes and starts TaskScheduler with default params. |
+base::TaskScheduler::CreateAndStartWithDefaultParams(“process_name”); |
+// The base/task_scheduler/post_task.h API can now be used. Tasks will be |
+// scheduled as they are posted. |
+ |
+// This initializes TaskScheduler. |
+base::TaskScheduler::Create(“process_name”); |
+// The base/task_scheduler/post_task.h API can now be used. No threads |
+// will be created and no tasks will be scheduled until after Start() is called. |
+base::TaskScheduler::GetInstance()->Start(params); |
+// TaskScheduler can now create threads and schedule tasks. |
+``` |
+ |
+And shutdown TaskScheduler late in the main function: |
+ |
+```cpp |
+base::TaskScheduler::GetInstance()->Shutdown(); |
+// Tasks posted with TaskShutdownBehavior::BLOCK_SHUTDOWN and |
+// tasks posted with TaskShutdownBehavior::SKIP_ON_SHUTDOWN that |
+// have started to run before the Shutdown() call have now completed their |
+// execution. Tasks posted with |
+// TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN may still be |
+// running. |
+``` |