• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_FUNCTIONAL_CONCURRENT_CLOSURES_H_
6 #define BASE_FUNCTIONAL_CONCURRENT_CLOSURES_H_
7 
8 #include "base/base_export.h"
9 #include "base/functional/callback.h"
10 #include "base/location.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/sequence_checker.h"
13 #include "base/task/bind_post_task.h"
14 
15 namespace base {
16 
17 // OVERVIEW:
18 //
19 // ConcurrentClosures is a OnceClosure version of ConcurrentCallbacks<T> and an
20 // alternative to BarrierClosure, it dispenses OnceClosures via CreateClosure()
21 // and invokes the closure passed to Done() after all prior closures have been
22 // run.
23 //
24 // ConcurrentClosures is intended to be used over BarrierClosure in
25 // cases where the count is unknown prior to requiring a closure to start a
26 // task, and for cases where the count is manually derived from the code and
27 // subject to human error.
28 //
29 // IMPORTANT NOTES:
30 //
31 // - ConcurrentClosures is NOT thread safe.
32 // - The done closure will NOT be run synchronously, it will be PostTask() to
33 //   the sequence that Done() was invoked on.
34 // - ConcurrentClosures cannot be used after Done() is called, a CHECK verifies
35 //   this.
36 //
37 // TYPICAL USAGE:
38 //
39 // void DoABC(OnceClosure closure) {
40 //   base::ConcurrentClosures concurrent;
41 //
42 //   DoA(concurrent.CreateClosure());
43 //   DoB(concurrent.CreateClosure());
44 //   DoC(concurrent.CreateClosure());
45 //
46 //   std::move(concurrent).Done(closure);
47 // }
48 
49 class BASE_EXPORT ConcurrentClosures {
50  public:
51   ConcurrentClosures();
52   ~ConcurrentClosures();
53 
54   // Create a closure for the done closure to wait for.
55   [[nodiscard]] OnceClosure CreateClosure();
56 
57   // Finish creating concurrent closures and provide done closure to run once
58   // all prior closures have executed.
59   // `this` is no longer usable after calling Done(), must be called with
60   // std::move().
61   void Done(OnceClosure done_closure, const Location& location = FROM_HERE) &&;
62 
63  private:
64   class Info {
65    public:
66     Info();
67     ~Info();
68 
69     void Run();
70 
71     size_t pending_ GUARDED_BY_CONTEXT(sequence_checker_) = 0u;
72     OnceClosure done_closure_ GUARDED_BY_CONTEXT(sequence_checker_);
73     SEQUENCE_CHECKER(sequence_checker_);
74   };
75 
76   RepeatingClosure info_run_closure_;
77   // info_ is owned by info_run_closure_.
78   raw_ptr<Info> info_;
79 };
80 
81 }  // namespace base
82 
83 #endif  // BASE_FUNCTIONAL_CONCURRENT_CLOSURES_H_
84