2 * Copyright 2016 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.
19 #include <gtest/gtest.h>
26 #include <glog/logging.h>
27 #include <folly/Foreach.h>
28 #include <folly/Random.h>
29 #include <folly/Synchronized.h>
32 inline std::mt19937& getRNG() {
33 static const auto seed = folly::randomNumberSeed();
34 static std::mt19937 rng(seed);
38 template <class Integral1, class Integral2>
39 Integral2 random(Integral1 low, Integral2 up) {
40 std::uniform_int_distribution<> range(low, up);
41 return range(getRNG());
44 template <class Mutex>
46 folly::Synchronized<std::vector<int>, Mutex> obj;
51 EXPECT_EQ(obj2->size(), 1000);
55 EXPECT_EQ(obj.size(), 1001);
56 EXPECT_EQ(obj.back(), 10);
57 EXPECT_EQ(obj2->size(), 1000);
60 EXPECT_EQ(obj->size(), 1001);
64 SYNCHRONIZED_CONST (obj) {
65 EXPECT_EQ(obj.size(), 1001);
67 EXPECT_EQ(obj->size(), 1001);
71 SYNCHRONIZED (lockedObj, *&obj) {
72 lockedObj.front() = 2;
75 EXPECT_EQ(obj->size(), 1001);
76 EXPECT_EQ(obj->back(), 10);
77 EXPECT_EQ(obj2->size(), 1000);
79 EXPECT_EQ(FB_ARG_2_OR_1(1, 2), 2);
80 EXPECT_EQ(FB_ARG_2_OR_1(1), 1);
83 template <class Mutex> void testConcurrency() {
84 folly::Synchronized<std::vector<int>, Mutex> v;
87 static bool threadMain(int i,
88 folly::Synchronized<std::vector<int>, Mutex>& pv) {
89 usleep(::random(100 * 1000, 1000 * 1000));
94 // Aaand test the SYNCHRONIZED macro
95 SYNCHRONIZED (v, pv) {
96 v.push_back(2 * i + 1);
103 std::vector<std::thread> results;
105 static const size_t threads = 100;
106 FOR_EACH_RANGE (i, 0, threads) {
107 results.push_back(std::thread([&, i]() { Local::threadMain(i, v); }));
110 FOR_EACH (i, results) {
114 std::vector<int> result;
117 EXPECT_EQ(result.size(), 2 * threads);
118 sort(result.begin(), result.end());
120 FOR_EACH_RANGE (i, 0, 2 * threads) {
121 EXPECT_EQ(result[i], i);
125 template <class Mutex> void testDualLocking() {
126 folly::Synchronized<std::vector<int>, Mutex> v;
127 folly::Synchronized<std::map<int, int>, Mutex> m;
130 static bool threadMain(
132 folly::Synchronized<std::vector<int>, Mutex>& pv,
133 folly::Synchronized<std::map<int, int>, Mutex>& pm) {
135 usleep(::random(100 * 1000, 1000 * 1000));
138 SYNCHRONIZED_DUAL (v, pv, m, pm) {
143 SYNCHRONIZED_DUAL (m, pm, v, pv) {
153 std::vector<std::thread> results;
155 static const size_t threads = 100;
156 FOR_EACH_RANGE (i, 0, threads) {
158 std::thread([&, i]() { Local::threadMain(i, v, m); }));
161 FOR_EACH (i, results) {
165 std::vector<int> result;
168 EXPECT_EQ(result.size(), threads);
169 sort(result.begin(), result.end());
171 FOR_EACH_RANGE (i, 0, threads) {
172 EXPECT_EQ(result[i], i);
176 template <class Mutex> void testDualLockingWithConst() {
177 folly::Synchronized<std::vector<int>, Mutex> v;
178 folly::Synchronized<std::map<int, int>, Mutex> m;
181 static bool threadMain(
183 folly::Synchronized<std::vector<int>, Mutex>& pv,
184 const folly::Synchronized<std::map<int, int>, Mutex>& pm) {
186 usleep(::random(100 * 1000, 1000 * 1000));
189 SYNCHRONIZED_DUAL (v, pv, m, pm) {
194 SYNCHRONIZED_DUAL (m, pm, v, pv) {
204 std::vector<std::thread> results;
206 static const size_t threads = 100;
207 FOR_EACH_RANGE (i, 0, threads) {
209 std::thread([&, i]() { Local::threadMain(i, v, m); }));
212 FOR_EACH (i, results) {
216 std::vector<int> result;
219 EXPECT_EQ(result.size(), threads);
220 sort(result.begin(), result.end());
222 FOR_EACH_RANGE (i, 0, threads) {
223 EXPECT_EQ(result[i], i);
227 template <class Mutex> void testTimedSynchronized() {
228 folly::Synchronized<std::vector<int>, Mutex> v;
231 static bool threadMain(int i,
232 folly::Synchronized<std::vector<int>, Mutex>& pv) {
233 usleep(::random(100 * 1000, 1000 * 1000));
236 pv->push_back(2 * i);
238 // Aaand test the TIMED_SYNCHRONIZED macro
240 TIMED_SYNCHRONIZED (10, v, pv) {
242 usleep(::random(15 * 1000, 150 * 1000));
243 v->push_back(2 * i + 1);
248 usleep(::random(10 * 1000, 100 * 1000));
256 std::vector<std::thread> results;
258 static const size_t threads = 100;
259 FOR_EACH_RANGE (i, 0, threads) {
260 results.push_back(std::thread([&, i]() { Local::threadMain(i, v); }));
263 FOR_EACH (i, results) {
267 std::vector<int> result;
270 EXPECT_EQ(result.size(), 2 * threads);
271 sort(result.begin(), result.end());
273 FOR_EACH_RANGE (i, 0, 2 * threads) {
274 EXPECT_EQ(result[i], i);
278 template <class Mutex> void testTimedSynchronizedWithConst() {
279 folly::Synchronized<std::vector<int>, Mutex> v;
282 static bool threadMain(int i,
283 folly::Synchronized<std::vector<int>, Mutex>& pv) {
284 usleep(::random(100 * 1000, 1000 * 1000));
289 usleep(::random(5 * 1000, 1000 * 1000));
290 // Test TIMED_SYNCHRONIZED_CONST
292 TIMED_SYNCHRONIZED_CONST (10, v, pv) {
294 auto found = std::find(v->begin(), v->end(), i);
295 CHECK(found != v->end());
299 usleep(::random(10 * 1000, 100 * 1000));
306 std::vector<std::thread> results;
308 static const size_t threads = 100;
309 FOR_EACH_RANGE (i, 0, threads) {
310 results.push_back(std::thread([&, i]() { Local::threadMain(i, v); }));
313 FOR_EACH (i, results) {
317 std::vector<int> result;
320 EXPECT_EQ(result.size(), threads);
321 sort(result.begin(), result.end());
323 FOR_EACH_RANGE (i, 0, threads) {
324 EXPECT_EQ(result[i], i);
328 template <class Mutex> void testConstCopy() {
329 std::vector<int> input = {1, 2, 3};
330 const folly::Synchronized<std::vector<int>, Mutex> v(input);
332 std::vector<int> result;
335 EXPECT_EQ(result, input);
338 EXPECT_EQ(result, input);
341 struct NotCopiableNotMovable {
342 NotCopiableNotMovable(int, const char*) {}
343 NotCopiableNotMovable(const NotCopiableNotMovable&) = delete;
344 NotCopiableNotMovable& operator=(const NotCopiableNotMovable&) = delete;
345 NotCopiableNotMovable(NotCopiableNotMovable&&) = delete;
346 NotCopiableNotMovable& operator=(NotCopiableNotMovable&&) = delete;
349 template <class Mutex> void testInPlaceConstruction() {
350 // This won't compile without construct_in_place
351 folly::Synchronized<NotCopiableNotMovable> a(
352 folly::construct_in_place, 5, "a"