proxygen
CallOnce.h
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <atomic>
20 #include <mutex>
21 #include <utility>
22 
23 #include <folly/Likely.h>
24 #include <folly/Portability.h>
25 #include <folly/SharedMutex.h>
27 
28 namespace folly {
29 
30 template <typename Mutex, template <typename> class Atom = std::atomic>
32 
33 // call_once
34 //
35 // Drop-in replacement for std::call_once.
36 //
37 // The libstdc++ implementation has two flaws:
38 // * it lacks a fast path, and
39 // * it deadlocks (in explicit violation of the standard) when invoked twice
40 // with a given flag, and the callable passed to the first invocation throws.
41 //
42 // This implementation corrects both flaws.
43 //
44 // The tradeoff is a slightly larger once_flag struct at 8 bytes, vs 4 bytes
45 // with libstdc++ on Linux/x64.
46 //
47 // Does not work with std::once_flag.
48 //
49 // mimic: std::call_once
50 template <
51  typename Mutex,
52  template <typename> class Atom,
53  typename F,
54  typename... Args>
57  flag.call_once(std::forward<F>(f), std::forward<Args>(args)...);
58 }
59 
60 // basic_once_flag
61 //
62 // The flag template to be used with call_once. Parameterizable by the mutex
63 // type and atomic template. The mutex type is required to mimic std::mutex and
64 // the atomic type is required to mimic std::atomic.
65 template <typename Mutex, template <typename> class Atom>
66 class basic_once_flag {
67  public:
68  constexpr basic_once_flag() noexcept = default;
69  basic_once_flag(const basic_once_flag&) = delete;
70  basic_once_flag& operator=(const basic_once_flag&) = delete;
71 
72  private:
73  template <
74  typename Mutex_,
75  template <typename> class Atom_,
76  typename F,
77  typename... Args>
78  friend void call_once(basic_once_flag<Mutex_, Atom_>&, F&&, Args&&...);
79 
80  template <typename F, typename... Args>
81  FOLLY_ALWAYS_INLINE void call_once(F&& f, Args&&... args) {
82  if (LIKELY(called_.load(std::memory_order_acquire))) {
83  return;
84  }
85  call_once_slow(std::forward<F>(f), std::forward<Args>(args)...);
86  }
87 
88  template <typename F, typename... Args>
89  FOLLY_NOINLINE void call_once_slow(F&& f, Args&&... args) {
90  std::lock_guard<Mutex> lock(mutex_);
91  if (called_.load(std::memory_order_relaxed)) {
92  return;
93  }
94  invoke(std::forward<F>(f), std::forward<Args>(args)...);
95  called_.store(true, std::memory_order_release);
96  }
97 
98  Atom<bool> called_{false};
100 };
101 
102 // once_flag
103 //
104 // The flag type to be used with call_once. An instance of basic_once_flag.
105 //
106 // Does not work with sd::call_once.
107 //
108 // mimic: std::once_flag
110 
111 } // namespace folly
auto f
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
#define LIKELY(x)
Definition: Likely.h:47
#define Mutex
basic_once_flag & operator=(const basic_once_flag &)=delete
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
static once_flag flag
Definition: Random.cpp:75
FOLLY_ALWAYS_INLINE void call_once(basic_once_flag< Mutex, Atom > &flag, F &&f, Args &&...args)
Definition: CallOnce.h:56
#define FOLLY_NOINLINE
Definition: CPortability.h:142
constexpr auto invoke(F &&f, Args &&...args) noexcept(noexcept(static_cast< F && >(f)(static_cast< Args && >(args)...))) -> decltype(static_cast< F && >(f)(static_cast< Args && >(args)...))
Definition: Invoke.h:49
#define Atom
FOLLY_ALWAYS_INLINE void call_once(F &&f, Args &&...args)
Definition: CallOnce.h:81
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
friend void call_once(basic_once_flag< Mutex_, Atom_ > &, F &&, Args &&...)
Atom< bool > called_
Definition: CallOnce.h:98
constexpr basic_once_flag() noexcept=default
FOLLY_NOINLINE void call_once_slow(F &&f, Args &&...args)
Definition: CallOnce.h:89