2 * Copyright 2015 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.
17 #ifndef FOLLY_TEST_SYNCHRONIZEDTESTLIB_INL_H
18 #define FOLLY_TEST_SYNCHRONIZEDTESTLIB_INL_H
20 #include <gtest/gtest.h>
27 #include <glog/logging.h>
28 #include <folly/Foreach.h>
29 #include <folly/Random.h>
30 #include <folly/Synchronized.h>
33 inline std::mt19937& getRNG() {
34 static const auto seed = folly::randomNumberSeed();
35 static std::mt19937 rng(seed);
39 template <class Integral1, class Integral2>
40 Integral2 random(Integral1 low, Integral2 up) {
41 std::uniform_int_distribution<> range(low, up);
42 return range(getRNG());
45 template <class Mutex>
47 folly::Synchronized<std::vector<int>, Mutex> obj;
52 EXPECT_EQ(obj2->size(), 1000);
56 EXPECT_EQ(obj.size(), 1001);
57 EXPECT_EQ(obj.back(), 10);
58 EXPECT_EQ(obj2->size(), 1000);
61 EXPECT_EQ(obj->size(), 1001);
65 SYNCHRONIZED_CONST (obj) {
66 EXPECT_EQ(obj.size(), 1001);
68 EXPECT_EQ(obj->size(), 1001);
72 SYNCHRONIZED (lockedObj, *&obj) {
73 lockedObj.front() = 2;
76 EXPECT_EQ(obj->size(), 1001);
77 EXPECT_EQ(obj->back(), 10);
78 EXPECT_EQ(obj2->size(), 1000);
80 EXPECT_EQ(FB_ARG_2_OR_1(1, 2), 2);
81 EXPECT_EQ(FB_ARG_2_OR_1(1), 1);
84 template <class Mutex> void testConcurrency() {
85 folly::Synchronized<std::vector<int>, Mutex> v;
88 static bool threadMain(int i,
89 folly::Synchronized<std::vector<int>, Mutex>& pv) {
90 usleep(::random(100 * 1000, 1000 * 1000));
95 // Aaand test the SYNCHRONIZED macro
96 SYNCHRONIZED (v, pv) {
97 v.push_back(2 * i + 1);
104 std::vector<std::thread> results;
106 static const size_t threads = 100;
107 FOR_EACH_RANGE (i, 0, threads) {
108 results.push_back(std::thread([&, i]() { Local::threadMain(i, v); }));
111 FOR_EACH (i, results) {
115 std::vector<int> result;
118 EXPECT_EQ(result.size(), 2 * threads);
119 sort(result.begin(), result.end());
121 FOR_EACH_RANGE (i, 0, 2 * threads) {
122 EXPECT_EQ(result[i], i);
126 template <class Mutex> void testDualLocking() {
127 folly::Synchronized<std::vector<int>, Mutex> v;
128 folly::Synchronized<std::map<int, int>, Mutex> m;
131 static bool threadMain(
133 folly::Synchronized<std::vector<int>, Mutex>& pv,
134 folly::Synchronized<std::map<int, int>, Mutex>& pm) {
136 usleep(::random(100 * 1000, 1000 * 1000));
139 SYNCHRONIZED_DUAL (v, pv, m, pm) {
144 SYNCHRONIZED_DUAL (m, pm, v, pv) {
154 std::vector<std::thread> results;
156 static const size_t threads = 100;
157 FOR_EACH_RANGE (i, 0, threads) {
159 std::thread([&, i]() { Local::threadMain(i, v, m); }));
162 FOR_EACH (i, results) {
166 std::vector<int> result;
169 EXPECT_EQ(result.size(), threads);
170 sort(result.begin(), result.end());
172 FOR_EACH_RANGE (i, 0, threads) {
173 EXPECT_EQ(result[i], i);
177 template <class Mutex> void testDualLockingWithConst() {
178 folly::Synchronized<std::vector<int>, Mutex> v;
179 folly::Synchronized<std::map<int, int>, Mutex> m;
182 static bool threadMain(
184 folly::Synchronized<std::vector<int>, Mutex>& pv,
185 const folly::Synchronized<std::map<int, int>, Mutex>& pm) {
187 usleep(::random(100 * 1000, 1000 * 1000));
190 SYNCHRONIZED_DUAL (v, pv, m, pm) {
195 SYNCHRONIZED_DUAL (m, pm, v, pv) {
205 std::vector<std::thread> results;
207 static const size_t threads = 100;
208 FOR_EACH_RANGE (i, 0, threads) {
210 std::thread([&, i]() { Local::threadMain(i, v, m); }));
213 FOR_EACH (i, results) {
217 std::vector<int> result;
220 EXPECT_EQ(result.size(), threads);
221 sort(result.begin(), result.end());
223 FOR_EACH_RANGE (i, 0, threads) {
224 EXPECT_EQ(result[i], i);
228 template <class Mutex> void testTimedSynchronized() {
229 folly::Synchronized<std::vector<int>, Mutex> v;
232 static bool threadMain(int i,
233 folly::Synchronized<std::vector<int>, Mutex>& pv) {
234 usleep(::random(100 * 1000, 1000 * 1000));
237 pv->push_back(2 * i);
239 // Aaand test the TIMED_SYNCHRONIZED macro
241 TIMED_SYNCHRONIZED (10, v, pv) {
243 usleep(::random(15 * 1000, 150 * 1000));
244 v->push_back(2 * i + 1);
249 usleep(::random(10 * 1000, 100 * 1000));
257 std::vector<std::thread> results;
259 static const size_t threads = 100;
260 FOR_EACH_RANGE (i, 0, threads) {
261 results.push_back(std::thread([&, i]() { Local::threadMain(i, v); }));
264 FOR_EACH (i, results) {
268 std::vector<int> result;
271 EXPECT_EQ(result.size(), 2 * threads);
272 sort(result.begin(), result.end());
274 FOR_EACH_RANGE (i, 0, 2 * threads) {
275 EXPECT_EQ(result[i], i);
279 template <class Mutex> void testTimedSynchronizedWithConst() {
280 folly::Synchronized<std::vector<int>, Mutex> v;
283 static bool threadMain(int i,
284 folly::Synchronized<std::vector<int>, Mutex>& pv) {
285 usleep(::random(100 * 1000, 1000 * 1000));
290 usleep(::random(5 * 1000, 1000 * 1000));
291 // Test TIMED_SYNCHRONIZED_CONST
293 TIMED_SYNCHRONIZED_CONST (10, v, pv) {
295 auto found = std::find(v->begin(), v->end(), i);
296 CHECK(found != v->end());
300 usleep(::random(10 * 1000, 100 * 1000));
307 std::vector<std::thread> results;
309 static const size_t threads = 100;
310 FOR_EACH_RANGE (i, 0, threads) {
311 results.push_back(std::thread([&, i]() { Local::threadMain(i, v); }));
314 FOR_EACH (i, results) {
318 std::vector<int> result;
321 EXPECT_EQ(result.size(), threads);
322 sort(result.begin(), result.end());
324 FOR_EACH_RANGE (i, 0, threads) {
325 EXPECT_EQ(result[i], i);
329 template <class Mutex> void testConstCopy() {
330 std::vector<int> input = {1, 2, 3};
331 const folly::Synchronized<std::vector<int>, Mutex> v(input);
333 std::vector<int> result;
336 EXPECT_EQ(result, input);
339 EXPECT_EQ(result, input);
342 struct NotCopiableNotMovable {
343 NotCopiableNotMovable(int, const char*) {}
344 NotCopiableNotMovable(const NotCopiableNotMovable&) = delete;
345 NotCopiableNotMovable& operator=(const NotCopiableNotMovable&) = delete;
346 NotCopiableNotMovable(NotCopiableNotMovable&&) = delete;
347 NotCopiableNotMovable& operator=(NotCopiableNotMovable&&) = delete;
350 template <class Mutex> void testInPlaceConstruction() {
351 // This won't compile without construct_in_place
352 folly::Synchronized<NotCopiableNotMovable> a(
353 folly::construct_in_place, 5, "a"
358 #endif /* FOLLY_TEST_SYNCHRONIZEDTESTLIB_INL_H */