2 * Copyright 2017-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <folly/concurrency/AtomicSharedPtr.h>
21 #include <condition_variable>
27 using std::shared_ptr;
28 using std::make_shared;
32 using std::condition_variable;
33 using std::unique_lock;
37 using std::memory_order;
38 using std::memory_order_relaxed;
39 using std::memory_order_acquire;
40 using std::memory_order_release;
41 using std::memory_order_acq_rel;
42 using std::memory_order_seq_cst;
47 using std::chrono::steady_clock;
48 using std::chrono::duration_cast;
49 using std::chrono::microseconds;
51 static uint64_t nowMicro() {
52 return duration_cast<microseconds>(steady_clock::now().time_since_epoch())
56 static const char* memoryOrder(memory_order order) {
58 case memory_order_relaxed:
60 case memory_order_acquire:
62 case memory_order_release:
64 case memory_order_acq_rel:
66 case memory_order_seq_cst:
74 void uncontended_read_write(
77 memory_order readOrder = memory_order_seq_cst,
78 memory_order writeOrder = memory_order_seq_cst) {
79 std::shared_ptr<int> zero = std::make_shared<int>(0);
81 auto time1 = nowMicro();
82 for (size_t i = 0; i < 10000000; ++i) {
83 for (size_t j = 0; j < readers; ++j) {
86 for (size_t j = 0; j < writers; ++j) {
87 a.store(zero, writeOrder);
90 auto time2 = nowMicro();
91 cout << "Uncontended Read(" << readers << "," << memoryOrder(readOrder)
92 << ")/Write(" << writers << "," << memoryOrder(writeOrder)
93 << "): " << (time2 - time1) << " \u03BCs" << endl;
98 unique_lock<mutex> lock,
99 condition_variable& cvar,
102 memory_order order) {
103 cvar.wait(lock, [&go]() {
104 return atomic_load_explicit(&go, memory_order_acquire);
107 for (size_t i = 0; i < 1000000; ++i) {
112 template <typename T>
114 unique_lock<mutex> lock,
115 condition_variable& cvar,
118 memory_order order) {
119 std::shared_ptr<int> zero = std::make_shared<int>(0);
120 cvar.wait(lock, [&go]() {
121 return atomic_load_explicit(&go, memory_order_acquire);
124 for (size_t i = 0; i < 1000000; ++i) {
125 aptr.store(zero, order);
129 template <typename T>
130 void contended_read_write(
133 memory_order readOrder = memory_order_seq_cst,
134 memory_order writeOrder = memory_order_seq_cst) {
135 vector<thread> threads;
137 condition_variable cvar;
138 atomic<bool> go{false};
139 T aptr(std::make_shared<int>());
140 for (size_t i = 0; i < readers; ++i) {
141 unique_lock<mutex> ulock(lock);
142 threads.emplace_back(
143 &read_asp<T>, move(ulock), ref(cvar), ref(go), ref(aptr), readOrder);
145 for (size_t i = 0; i < writers; ++i) {
146 unique_lock<mutex> ulock(lock);
147 threads.emplace_back(
148 &write_asp<T>, move(ulock), ref(cvar), ref(go), ref(aptr), writeOrder);
150 unique_lock<mutex> ulock(lock);
152 atomic_store_explicit(&go, true, memory_order_release);
153 auto time1 = nowMicro();
155 for (auto& thread : threads) {
158 auto time2 = nowMicro();
159 cout << "Contended Read(" << readers << "," << memoryOrder(readOrder)
160 << ")/Write(" << writers << "," << memoryOrder(writeOrder)
161 << "): " << (time2 - time1) << " \u03BCs" << endl;
164 template <typename T>
165 void document_noexcept() {
166 shared_ptr<int> ptr = make_shared<int>(0);
168 cout << " ctor () is " << (noexcept(T()) ? "" : "not ") << "noexcept."
170 cout << " ctor (ptr) is " << (noexcept(T(ptr)) ? "" : "not ") << "noexcept."
174 cout << " " #A " is " << (noexcept(aptr.A) ? "" : "not ") << "noexcept." \
182 _(store(ptr, memory_order_seq_cst));
185 _(load(memory_order_seq_cst));
188 _(exchange(ptr, memory_order_seq_cst));
190 _(compare_exchange_strong(ptr, ptr));
191 _(compare_exchange_strong(ptr, ptr, memory_order_seq_cst));
192 _(compare_exchange_strong(
193 ptr, ptr, memory_order_seq_cst, memory_order_seq_cst));
195 _(compare_exchange_weak(ptr, ptr));
196 _(compare_exchange_weak(ptr, ptr, memory_order_seq_cst));
197 _(compare_exchange_weak(
198 ptr, ptr, memory_order_seq_cst, memory_order_seq_cst));
201 cout << " operator std::shared_ptr<T>() is "
202 << (noexcept(ptr = aptr) ? "" : "not ") << "noexcept." << endl;
205 template <typename T>
207 document_noexcept<T>();
208 uncontended_read_write<T>(10, 0);
209 uncontended_read_write<T>(0, 10);
210 uncontended_read_write<T>(10, 10);
211 uncontended_read_write<T>(10, 10, memory_order_relaxed, memory_order_relaxed);
212 uncontended_read_write<T>(10, 10, memory_order_acquire, memory_order_release);
213 contended_read_write<T>(10, 0);
214 contended_read_write<T>(0, 10);
215 contended_read_write<T>(1, 1);
216 contended_read_write<T>(5, 1);
217 contended_read_write<T>(10, 1);
218 contended_read_write<T>(100, 1);
219 contended_read_write<T>(100, 1, memory_order_relaxed, memory_order_relaxed);
220 contended_read_write<T>(100, 1, memory_order_acquire, memory_order_release);
223 int main(int, char**) {
224 cout << endl << "Folly implementation. Is lock free: 1" << endl;
225 runSuite<folly::atomic_shared_ptr<int>>();