23 #include <glog/logging.h> 25 #include <condition_variable> 33 namespace sync_tests {
42 std::uniform_int_distribution<>
range(min.count(), max.count());
43 std::chrono::milliseconds duration(
range(
getRNG()));
45 std::this_thread::sleep_for(duration);
56 template <
class Function>
58 std::vector<std::thread>
threads;
59 threads.reserve(numThreads);
64 std::condition_variable readyCV;
66 std::condition_variable goCV;
68 auto worker = [&](
size_t threadIndex) {
70 ++(*threadsReady.lock());
77 auto lockedGo = go.lock();
78 goCV.wait(lockedGo.getUniqueLock(), [&] {
return *lockedGo; });
81 function(threadIndex);
85 for (
size_t threadIndex = 0; threadIndex < numThreads; ++threadIndex) {
86 threads.emplace_back([threadIndex, &worker]() { worker(threadIndex); });
91 auto readyLocked = threadsReady.lock();
92 readyCV.wait(readyLocked.getUniqueLock(), [&] {
93 return *readyLocked == numThreads;
101 for (
auto& thread : threads) {
107 template <
class Mutex>
108 typename std::enable_if<folly::LockTraits<Mutex>::is_shared>
::type 111 const auto& constObj = obj;
113 obj.wlock()->resize(1000);
119 auto lockedObj = obj.wlock();
120 lockedObj->push_back(10);
127 auto unlocker = lockedObj.scopedUnlock();
133 auto lockedObj = obj.rlock();
137 auto unlocker = lockedObj.scopedUnlock();
142 obj.wlock()->front() = 2;
159 template <
class Mutex>
160 typename std::enable_if<!folly::LockTraits<Mutex>::is_shared>
::type 163 const auto& constObj = obj;
165 obj.lock()->resize(1000);
171 auto lockedObj = obj.lock();
172 lockedObj->push_back(10);
178 auto unlocker = lockedObj.scopedUnlock();
183 auto lockedObj = constObj.lock();
189 obj.lock()->front() = 2;
198 template <
class Mutex>
200 testBasicImpl<Mutex>();
204 template <
class Mutex>
205 typename std::enable_if<folly::LockTraits<Mutex>::is_shared>
::type 208 const auto& constObj = obj;
211 obj.withWLock([](std::vector<int>& lockedObj) {
212 lockedObj.resize(1000);
213 lockedObj.push_back(10);
214 lockedObj.push_back(11);
216 obj.withWLock([](
const std::vector<int>& lockedObj) {
219 obj.withRLock([](
const std::vector<int>& lockedObj) {
223 constObj.withRLock([](
const std::vector<int>& lockedObj) {
227 #if __cpp_generic_lambdas >= 201304 228 obj.withWLock([](
auto& lockedObj) { lockedObj.push_back(12); });
230 [](
const auto& lockedObj) {
EXPECT_EQ(1003, lockedObj.size()); });
231 obj.withRLock([](
const auto& lockedObj) {
236 [](
const auto& lockedObj) {
EXPECT_EQ(1003, lockedObj.size()); });
237 obj.withWLock([](
auto& lockedObj) { lockedObj.pop_back(); });
242 #if __cpp_generic_lambdas >= 201304 243 obj.withWLockPtr([](
auto&& lockedObj) { lockedObj->push_back(13); });
244 obj.withRLockPtr([](
auto&& lockedObj) {
248 constObj.withRLockPtr([](
auto&& lockedObj) {
252 obj.withWLockPtr([&](
auto&& lockedObj) {
253 lockedObj->push_back(14);
255 auto unlocker = lockedObj.scopedUnlock();
256 obj.wlock()->push_back(15);
261 obj.withWLockPtr([](
typename SynchType::LockedPtr&& lockedObj) {
262 lockedObj->push_back(13);
263 lockedObj->push_back(14);
264 lockedObj->push_back(15);
268 obj.withWLockPtr([](
typename SynchType::LockedPtr&& lockedObj) {
269 lockedObj->push_back(16);
272 obj.withRLockPtr([](
typename SynchType::ConstLockedPtr&& lockedObj) {
276 constObj.withRLockPtr([](
typename SynchType::ConstLockedPtr&& lockedObj) {
283 template <
class Mutex>
284 typename std::enable_if<!folly::LockTraits<Mutex>::is_shared>
::type 289 obj.withLock([](std::vector<int>& lockedObj) {
290 lockedObj.resize(1000);
291 lockedObj.push_back(10);
292 lockedObj.push_back(11);
294 obj.withLock([](
const std::vector<int>& lockedObj) {
298 #if __cpp_generic_lambdas >= 201304 299 obj.withLock([](
auto& lockedObj) { lockedObj.push_back(12); });
301 [](
const auto& lockedObj) {
EXPECT_EQ(1003, lockedObj.size()); });
302 obj.withLock([](
auto& lockedObj) { lockedObj.pop_back(); });
307 #if __cpp_generic_lambdas >= 201304 308 obj.withLockPtr([](
auto&& lockedObj) { lockedObj->push_back(13); });
309 obj.withLockPtr([](
auto&& lockedObj) {
313 obj.withLockPtr([&](
auto&& lockedObj) {
314 lockedObj->push_back(14);
316 auto unlocker = lockedObj.scopedUnlock();
317 obj.lock()->push_back(15);
323 obj.withLockPtr([](
typename SynchType::LockedPtr&& lockedObj) {
324 lockedObj->push_back(13);
325 lockedObj->push_back(14);
326 lockedObj->push_back(15);
330 obj.withLockPtr([](
typename SynchType::LockedPtr&& lockedObj) {
331 lockedObj->push_back(16);
334 const auto& constObj = obj;
335 constObj.withLockPtr([](
typename SynchType::ConstLockedPtr&& lockedObj) {
341 template <
class Mutex>
344 const auto& cv =
value;
347 auto lv =
value.contextualLock();
354 auto rlv = cv.contextualLock();
360 auto rlv2 = cv.contextualRLock();
364 lv =
value.contextualLock();
373 template <
class Mutex>
374 typename std::enable_if<folly::LockTraits<Mutex>::is_shared>
::type 378 auto lv =
value.wlock();
385 auto rlv =
value.rlock();
391 auto lv2 =
value.wlock();
402 testUnlockCommon<Mutex>();
406 template <
class Mutex>
407 typename std::enable_if<!folly::LockTraits<Mutex>::is_shared>
::type 411 auto lv =
value.lock();
418 auto lv2 =
value.lock();
436 testUnlockCommon<Mutex>();
440 template <
class Mutex>
461 lockedObj.front() = 2;
472 template <
class Mutex>
475 static const size_t numThreads = 100;
480 static const size_t itersPerThread = 100;
482 auto pushNumbers = [&](
size_t threadIdx) {
484 for (
size_t n = 0; n < itersPerThread; ++n) {
491 std::vector<int> result;
494 EXPECT_EQ(numThreads * itersPerThread, result.size());
495 sort(result.begin(), result.end());
497 for (
size_t i = 0;
i < itersPerThread * numThreads; ++
i) {
502 template <
class Mutex>
507 auto dualLockWorker = [&](
size_t threadIdx) {
514 (*std::get<1>(ret))[threadIdx] = threadIdx + 1;
518 (*std::get<0>(ret))[threadIdx] = threadIdx + 1;
521 static const size_t numThreads = 100;
524 std::vector<int> result;
528 sort(result.begin(), result.end());
530 for (
size_t i = 0;
i < numThreads; ++
i) {
535 template <
class Mutex>
540 auto dualLockWorker = [&](
size_t threadIdx) {
544 (void)std::get<1>(ret)->size();
548 (void)std::get<0>(ret)->size();
552 static const size_t numThreads = 100;
555 std::vector<int> result;
559 sort(result.begin(), result.end());
561 for (
size_t i = 0;
i < numThreads; ++
i) {
567 template <
class Mutex>
572 auto dualLockWorker = [&](
size_t threadIdx) {
575 lv.push_back(threadIdx);
576 lm[threadIdx] = threadIdx + 1;
580 lv.push_back(threadIdx);
581 lm[threadIdx] = threadIdx + 1;
585 static const size_t numThreads = 100;
588 std::vector<int> result;
592 sort(result.begin(), result.end());
594 for (
size_t i = 0;
i < numThreads; ++
i) {
600 template <
class Mutex>
605 auto dualLockWorker = [&](
size_t threadIdx) {
610 lv.push_back(threadIdx);
615 lv.push_back(threadIdx);
619 static const size_t numThreads = 100;
622 std::vector<int> result;
626 sort(result.begin(), result.end());
628 for (
size_t i = 0;
i < numThreads; ++
i) {
633 template <
class Mutex>
638 auto worker = [&](
size_t threadIdx) {
652 randomSleep(std::chrono::milliseconds(5), std::chrono::milliseconds(15));
653 lv->push_back(2 * threadIdx + 1);
658 static const size_t numThreads = 100;
661 std::vector<int> result;
664 EXPECT_EQ(2 * numThreads, result.size());
665 sort(result.begin(), result.end());
667 for (
size_t i = 0;
i < 2 * numThreads; ++
i) {
691 template <
class Mutex>
696 auto worker = [&](
size_t threadIdx) {
698 v.wlock()->push_back(threadIdx);
702 auto lv = v.rlock(std::chrono::milliseconds(10));
716 randomSleep(std::chrono::milliseconds(5), std::chrono::milliseconds(15));
717 auto found = std::find(lv->begin(), lv->end(), threadIdx);
718 CHECK(found != lv->end());
723 static const size_t numThreads = 100;
726 std::vector<int> result;
730 sort(result.begin(), result.end());
732 for (
size_t i = 0;
i < numThreads; ++
i) {
744 template <
class Mutex>
749 auto worker = [&](
size_t threadIdx) {
751 v->push_back(2 * threadIdx);
760 std::chrono::milliseconds(5), std::chrono::milliseconds(15));
761 lv->push_back(2 * threadIdx + 1);
770 static const size_t numThreads = 100;
773 std::vector<int> result;
776 EXPECT_EQ(2 * numThreads, result.size());
777 sort(result.begin(), result.end());
779 for (
size_t i = 0;
i < 2 * numThreads; ++
i) {
791 template <
class Mutex>
796 auto worker = [&](
size_t threadIdx) {
798 v->push_back(threadIdx);
813 std::chrono::milliseconds(5), std::chrono::milliseconds(15));
814 auto found = std::find(lv->begin(), lv->end(), threadIdx);
815 CHECK(found != lv->end());
824 static const size_t numThreads = 100;
827 std::vector<int> result;
831 sort(result.begin(), result.end());
833 for (
size_t i = 0;
i < numThreads; ++
i) {
840 LOG(
INFO) <<
"testTimedSynchronizedWithConst: " 844 template <
class Mutex>
846 std::vector<int> input = {1, 2, 3};
849 std::vector<int> result;
866 template <
class Mutex>
872 template <
class Mutex>
874 std::vector<int> input = {1, 2, 3};
876 std::vector<int>
next = {4, 5, 6};
878 EXPECT_EQ((std::vector<int>{{1, 2, 3}}), prev);
#define SYNCHRONIZED_CONST(...)
void testAcquireLockedWithConst()
void randomSleep(std::chrono::milliseconds min, std::chrono::milliseconds max)
void testTimedSynchronized()
#define FB_ARG_2_OR_1(...)
std::enable_if< folly::LockTraits< Mutex >::is_shared >::type testBasicImpl()
void swap(Synchronized &rhs)
#define SYNCHRONIZED_DUAL(n1, e1, n2, e2)
#define EXPECT_EQ(val1, val2)
void testInPlaceConstruction()
constexpr detail::Map< Move > move
LockedPtr contextualLock()
NotCopiableNotMovable & operator=(const NotCopiableNotMovable &)=delete
ConstLockedPtr contextualRLock() const
—— Concurrent Priority Queue Implementation ——
in_place_tag in_place(in_place_tag={})
void runParallel(size_t numThreads, const Function &function)
std::enable_if< folly::LockTraits< Mutex >::is_shared >::type testWithLock()
std::vector< std::thread::id > threads
void BENCHFUN() push_back(size_t iters, size_t arg)
NotCopiableNotMovable(int, const char *)
std::tuple< detail::LockedPtrType< Sync1 >, detail::LockedPtrType< Sync2 > > acquireLocked(Sync1 &l1, Sync2 &l2)
constexpr Range< Iter > range(Iter first, Iter last)
static map< string, int > m
void testTimedSynchronizedWithConst()
void testDualLockingWithConst()
#define TIMED_SYNCHRONIZED(timeout,...)
#define EXPECT_TRUE(condition)
#define SYNCHRONIZED(...)
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
#define EXPECT_FALSE(condition)
uint32_t randomNumberSeed()
std::enable_if< folly::LockTraits< Mutex >::is_shared >::type testUnlock()
void copy(T *target) const
#define TIMED_SYNCHRONIZED_CONST(timeout,...)