// Copyright 2018 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_THREADING_SEQUENCE_BOUND_H_ #define BASE_THREADING_SEQUENCE_BOUND_H_ #include <concepts> #include <new> #include <tuple> #include <type_traits> #include <utility> #include "base/check.h" #include "base/location.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" #include "base/threading/sequence_bound_internal.h" namespace base { // Performing blocking work on a different task runner is a common pattern for // improving responsiveness of foreground task runners. `SequenceBound<T>` // provides an abstraction for an owner object living on the owner sequence, to // construct, call methods on, and destroy an object of type T that lives on a // different sequence (the bound sequence). // // This makes it natural for code running on different sequences to be // partitioned along class boundaries, e.g.: // // class Tab { // private: // void OnScroll() { // // ... // io_helper_.AsyncCall(&IOHelper::SaveScrollPosition); // } // base::SequenceBound<IOHelper> io_helper_{GetBackgroundTaskRunner()}; // }; // // Note: `SequenceBound<T>` intentionally does not expose a raw pointer to the // managed `T` to ensure its internal sequence-safety invariants are not // violated. As a result, `AsyncCall()` cannot simply use `base::OnceCallback` // // SequenceBound also supports replies: // // class Database { // public: // int Query(int value) { // return value * value; // } // }; // // // SequenceBound itself is owned on // // `SequencedTaskRunner::GetCurrentDefault()`. The managed Database // // instance managed by it is constructed and owned on `GetDBTaskRunner()`. // base::SequenceBound<Database> db(GetDBTaskRunner()); // // // `Database::Query()` runs on `GetDBTaskRunner()`, but // // `reply_callback` will run on the owner task runner. // auto reply_callback = [] (int result) { // LOG(ERROR) << result; // Prints 25. // }; // db.AsyncCall(&Database::Query).WithArgs(5) // .Then(base::BindOnce(reply_callback)); // // // When `db` goes out of scope, the Database instance will also be // // destroyed via a task posted to `GetDBTaskRunner()`. // // Sequence safety: // // Const-qualified methods may be used concurrently from multiple sequences, // e.g. `AsyncCall()` or `is_null()`. Calls that are forwarded to the // managed `T` will be posted to the bound sequence and executed serially // there. // // Mutable methods (e.g. `Reset()`, destruction, or move assignment) require // external synchronization if used concurrently with any other methods, // including const-qualified methods. // // Advanced usage: // // Using `SequenceBound<std::unique_ptr<T>>` allows transferring ownership of an // already-constructed `T` to `SequenceBound`. This can be helpful for more // complex situations, where `T` needs to be constructed on a specific sequence // that is different from where `T` will ultimately live. // // Construction (via the constructor or emplace) takes a `std::unique_ptr<T>` // instead of forwarding the arguments to `T`'s constructor: // // std::unique_ptr<Database> db_impl = MakeDatabaseOnMainThread(); // base::SequenceBound<std::unique_ptr<Database>> db(GetDbTaskRunner(), // std::move(db_impl)); // // All other usage (e.g. `AsyncCall()`, `Reset()`) functions identically to a // regular `SequenceBound<T>`: // // // No need to dereference the `std::unique_ptr` explicitly: // db.AsyncCall(&Database::Query).WithArgs(5).Then(base::BindOnce(...)); template <typename T, typename CrossThreadTraits = sequence_bound_internal::CrossThreadTraits> class SequenceBound { … }; } // namespace base #endif // BASE_THREADING_SEQUENCE_BOUND_H_