blob: 48d4b9c6f37f6a1888a5d72b10bf4a79a5446ab5 [file] [log] [blame]
Alan Cuttere0c5a292024-01-17 23:54:111// 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"
Sylvain Defresnecb4f83a2024-05-16 20:47:5212#include "base/sequence_checker.h"
Alan Cuttere0c5a292024-01-17 23:54:1113#include "base/task/bind_post_task.h"
14
15namespace 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
49class 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
Sylvain Defresnecb4f83a2024-05-16 20:47:5271 size_t pending_ GUARDED_BY_CONTEXT(sequence_checker_) = 0u;
72 OnceClosure done_closure_ GUARDED_BY_CONTEXT(sequence_checker_);
73 SEQUENCE_CHECKER(sequence_checker_);
Alan Cuttere0c5a292024-01-17 23:54:1174 };
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_