From 2ae3ca9cbafd2aade3eb59d01ec1be51b5eaa092 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Thu, 22 Mar 2018 10:14:15 -0700 Subject: [PATCH 1/9] Modified spin lock to devolve to standard lock after 1000 spins Modified the spin lock to use something like a lock after 1000 spins. It uses a condition variable to wake it up when its ticket is called. Includes some temporary debugging configuration --- CMakeLists.txt | 49 ++++++++++++------------ aws/utils/spin_lock.h | 66 +++++++++++++++++++++++++++++++- aws/utils/test/spin_lock_test.cc | 47 +++++++++++++++++------ 3 files changed, 124 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80c74cd0..b0dffcf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,13 +7,13 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(ADDL_LINK_CONFIG "-static-libstdc++") add_compile_options("-fpermissive") endif() - +add_definitions(-DDEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug) add_definitions(-DDEBUG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") - if (CMAKE_COMPILER_IS_GNUCXX) - set(ADDL_LINK_CONFIG "${ADDL_LINK_CONFIG} -static-libasan") - endif (CMAKE_COMPILER_IS_GNUCXX) + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + # if (CMAKE_COMPILER_IS_GNUCXX) + # set(ADDL_LINK_CONFIG "${ADDL_LINK_CONFIG} -static-libasan") + # endif (CMAKE_COMPILER_IS_GNUCXX) endif(CMAKE_BUILD_TYPE MATCHES Debug) if(APPLE) @@ -71,6 +71,7 @@ set(SOURCE_FILES aws/utils/io_service_executor.h aws/utils/logging.cc aws/utils/logging.h + aws/utils/spin_lock.cc aws/utils/spin_lock.h aws/utils/time_sensitive.h aws/utils/time_sensitive_queue.h @@ -86,26 +87,26 @@ if(ENABLE_SEGFAULT_TRIGGER) endif(ENABLE_SEGFAULT_TRIGGER) set(TESTS_SOURCE - aws/utils/test/concurrent_hash_map_test.cc - aws/utils/test/concurrent_linked_queue_test.cc + # aws/utils/test/concurrent_hash_map_test.cc + # aws/utils/test/concurrent_linked_queue_test.cc aws/utils/test/spin_lock_test.cc - aws/utils/test/token_bucket_test.cc - aws/kinesis/core/test/aggregator_test.cc - aws/kinesis/core/test/ipc_manager_test.cc - aws/kinesis/core/test/kinesis_record_test.cc - aws/kinesis/core/test/limiter_test.cc - aws/kinesis/core/test/put_records_request_test.cc - aws/kinesis/core/test/reducer_test.cc - aws/kinesis/core/test/retrier_test.cc - aws/kinesis/core/test/shard_map_test.cc - aws/kinesis/core/test/test_utils.cc - aws/kinesis/core/test/test_utils.h - aws/kinesis/core/test/user_record_test.cc - aws/metrics/test/accumulator_test.cc - aws/metrics/test/metric_test.cc - aws/metrics/test/metrics_manager_test.cc - aws/auth/test/mutable_static_creds_provider_test.cc) - + # aws/utils/test/token_bucket_test.cc + # aws/kinesis/core/test/aggregator_test.cc + # aws/kinesis/core/test/ipc_manager_test.cc + # aws/kinesis/core/test/kinesis_record_test.cc + # aws/kinesis/core/test/limiter_test.cc + # aws/kinesis/core/test/put_records_request_test.cc + # aws/kinesis/core/test/reducer_test.cc + # aws/kinesis/core/test/retrier_test.cc + # aws/kinesis/core/test/shard_map_test.cc + # aws/kinesis/core/test/test_utils.cc + # aws/kinesis/core/test/test_utils.h + # aws/kinesis/core/test/user_record_test.cc + # aws/metrics/test/accumulator_test.cc + # aws/metrics/test/metric_test.cc + # aws/metrics/test/metrics_manager_test.cc + # aws/auth/test/mutable_static_creds_provider_test.cc) +) set(THIRD_PARTY_LIBS third_party/lib) set(THIRD_PARTY_INCLUDE third_party/include) diff --git a/aws/utils/spin_lock.h b/aws/utils/spin_lock.h index 3ddf673c..1a9a6e74 100644 --- a/aws/utils/spin_lock.h +++ b/aws/utils/spin_lock.h @@ -15,7 +15,10 @@ #define AWS_UTILS_SPIN_LOCK_H_ #include - +#include +#include +#include +#include #include namespace aws { @@ -27,22 +30,81 @@ class TicketSpinLock : boost::noncopyable { : now_serving_(0), next_ticket_(0) {} +#ifdef DEBUG + struct DebugStats { + std::uint64_t acquired_count; + std::uint64_t acquired_with_lock; + std::uint64_t total_spins; + }; + + void add_acquired(); + void add_acquired_lock(); + void add_spin(); + + DebugStats get_debug_stats(); +#else +#define add_acquired(); +#define add_acquired_lock(); +#define add_spin(); +#endif + + inline void lock() noexcept { size_t my_ticket = next_ticket_.fetch_add(1); - while (now_serving_ != my_ticket); + std::uint32_t spin_count = 0; + do { + add_spin(); + spin_count++; + if (spin_count > kMaxSpinCount) { + std::unique_lock lock(lock_for_ticket(my_ticket)); + cv_for_ticket(my_ticket).wait(lock, [this, &my_ticket] { return now_serving_ == my_ticket; }); + spin_count = 0; + add_acquired_lock(); + } + } while (now_serving_ != my_ticket); + add_acquired(); } inline void unlock() noexcept { now_serving_++; + std::unique_lock lock(lock_for_ticket(now_serving_)); + cv_for_ticket(now_serving_).notify_all(); } private: + inline std::size_t lock_shard(const std::size_t& ticket) noexcept { + return ticket % kLockShards; + } + inline std::mutex& lock_for_ticket(const std::size_t& ticket) noexcept { + return condition_locks_[lock_shard(ticket)]; + } + inline std::condition_variable& cv_for_ticket(const std::size_t& ticket) noexcept { + return unlocked_cv_[lock_shard(ticket)]; + } + static const std::uint32_t kMaxSpinCount = 1000; + + static const std::size_t kLockShards = 13; + std::array condition_locks_; + std::array unlocked_cv_; std::atomic now_serving_; std::atomic next_ticket_; + + }; class SpinLock : boost::noncopyable { public: + +#ifdef DEBUG + struct DebugStats { + std::uint64_t acquired_count; + std::uint64_t acquired_with_lock; + std::uint64_t total_spins; + }; + DebugStats get_debug_stats() { + return DebugStats(); + } +#endif inline void lock() noexcept { while (!try_lock()); } diff --git a/aws/utils/test/spin_lock_test.cc b/aws/utils/test/spin_lock_test.cc index e75d2aee..3a0dbb4c 100644 --- a/aws/utils/test/spin_lock_test.cc +++ b/aws/utils/test/spin_lock_test.cc @@ -33,9 +33,15 @@ void test(const std::string test_name, Mutex mutex; volatile size_t counter = 0; std::vector threads; +#ifdef DEBUG + std::vector debug_stats; + debug_stats.resize(num_threads); +#endif + std::size_t thread_count = 0; while (threads.size() < num_threads) { - threads.push_back(aws::thread([&] { + std::size_t thread_index = thread_count++; + threads.push_back(aws::thread([&, thread_index] { aws::utils::sleep_until(start); for (size_t i = 0; i < cycles_per_thread; i++) { aws::lock_guard lk(mutex); @@ -43,6 +49,9 @@ void test(const std::string test_name, counter++; } } +#ifdef DEBUG + debug_stats[thread_index] = mutex.get_debug_stats(); +#endif })); } @@ -58,28 +67,42 @@ void test(const std::string test_name, LOG(info) << test_name << ": " << num_threads << " threads: " << cycles_per_thread * num_threads / seconds << " ops per sec"; + +#ifdef DEBUG + LOG(info) << test_name << ": DebugStats"; + LOG(info) << "\t" + << std::setw(20) << "Acquired Count" + << std::setw(20) << "Acquired with Lock" + << std::setw(20) << "Total Spins"; + std::for_each(debug_stats.begin(), debug_stats.end(), [](typename Mutex::DebugStats& d) { + LOG(info) << "\t" + << std::setw(20) << d.acquired_count + << std::setw(20) << d.acquired_with_lock + << std::setw(20) << d.total_spins; + }); +#endif } } //namespace BOOST_AUTO_TEST_SUITE(SpinLock) -BOOST_AUTO_TEST_CASE(SpinLock) { - for (size_t i : {1, 4, 8}) { - test("SpinLock", i); - } -} +// BOOST_AUTO_TEST_CASE(SpinLock) { +// for (size_t i : {1, 4, 8}) { +// test("SpinLock", i); +// } +// } BOOST_AUTO_TEST_CASE(TicketSpinLock) { - for (size_t i : {1, 4, 8}) { + for (size_t i : {1, 4, 8, 16, 32}) { test("TicketSpinLock", i); } } -BOOST_AUTO_TEST_CASE(StdMutex) { - for (size_t i : {1, 4, 8}) { - test("std::mutex", i); - } -} +// BOOST_AUTO_TEST_CASE(StdMutex) { +// for (size_t i : {1, 4, 8}) { +// test("std::mutex", i); +// } +// } BOOST_AUTO_TEST_SUITE_END() From f94514cc7097081382ffabc25dbb4f87c41dbba8 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Thu, 22 Mar 2018 10:17:19 -0700 Subject: [PATCH 2/9] Forgot a file --- aws/utils/spin_lock.cc | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 aws/utils/spin_lock.cc diff --git a/aws/utils/spin_lock.cc b/aws/utils/spin_lock.cc new file mode 100644 index 00000000..f8396c69 --- /dev/null +++ b/aws/utils/spin_lock.cc @@ -0,0 +1,36 @@ +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). +// You may not use this file except in compliance with the License. +// A copy of the License is located at +// +// http://aws.amazon.com/asl +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +#include "spin_lock.h" + +using namespace aws::utils; + +namespace { + thread_local TicketSpinLock::DebugStats debug_stats; +} + +void TicketSpinLock::add_acquired() { + debug_stats.acquired_count++; +} + +void TicketSpinLock::add_acquired_lock() { + debug_stats.acquired_with_lock++; +} + +void TicketSpinLock::add_spin() { + debug_stats.total_spins++; +} + +TicketSpinLock::DebugStats TicketSpinLock::get_debug_stats() { + return debug_stats; +} From da4b7234097de61546fee18a1d89d5a8bd1e8859 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Thu, 22 Mar 2018 12:02:29 -0700 Subject: [PATCH 3/9] Restored some disabled tests --- CMakeLists.txt | 46 ++++++++++++++++---------------- aws/utils/spin_lock.cc | 3 ++- aws/utils/spin_lock.h | 4 +-- aws/utils/test/spin_lock_test.cc | 20 +++++++------- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b0dffcf2..bf6e87ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,13 +7,13 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(ADDL_LINK_CONFIG "-static-libstdc++") add_compile_options("-fpermissive") endif() -add_definitions(-DDEBUG) + if(CMAKE_BUILD_TYPE MATCHES Debug) add_definitions(-DDEBUG) - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") - # if (CMAKE_COMPILER_IS_GNUCXX) - # set(ADDL_LINK_CONFIG "${ADDL_LINK_CONFIG} -static-libasan") - # endif (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + if (CMAKE_COMPILER_IS_GNUCXX) + set(ADDL_LINK_CONFIG "${ADDL_LINK_CONFIG} -static-libasan") + endif (CMAKE_COMPILER_IS_GNUCXX) endif(CMAKE_BUILD_TYPE MATCHES Debug) if(APPLE) @@ -87,25 +87,25 @@ if(ENABLE_SEGFAULT_TRIGGER) endif(ENABLE_SEGFAULT_TRIGGER) set(TESTS_SOURCE - # aws/utils/test/concurrent_hash_map_test.cc - # aws/utils/test/concurrent_linked_queue_test.cc + aws/utils/test/concurrent_hash_map_test.cc + aws/utils/test/concurrent_linked_queue_test.cc aws/utils/test/spin_lock_test.cc - # aws/utils/test/token_bucket_test.cc - # aws/kinesis/core/test/aggregator_test.cc - # aws/kinesis/core/test/ipc_manager_test.cc - # aws/kinesis/core/test/kinesis_record_test.cc - # aws/kinesis/core/test/limiter_test.cc - # aws/kinesis/core/test/put_records_request_test.cc - # aws/kinesis/core/test/reducer_test.cc - # aws/kinesis/core/test/retrier_test.cc - # aws/kinesis/core/test/shard_map_test.cc - # aws/kinesis/core/test/test_utils.cc - # aws/kinesis/core/test/test_utils.h - # aws/kinesis/core/test/user_record_test.cc - # aws/metrics/test/accumulator_test.cc - # aws/metrics/test/metric_test.cc - # aws/metrics/test/metrics_manager_test.cc - # aws/auth/test/mutable_static_creds_provider_test.cc) + aws/utils/test/token_bucket_test.cc + aws/kinesis/core/test/aggregator_test.cc + aws/kinesis/core/test/ipc_manager_test.cc + aws/kinesis/core/test/kinesis_record_test.cc + aws/kinesis/core/test/limiter_test.cc + aws/kinesis/core/test/put_records_request_test.cc + aws/kinesis/core/test/reducer_test.cc + aws/kinesis/core/test/retrier_test.cc + aws/kinesis/core/test/shard_map_test.cc + aws/kinesis/core/test/test_utils.cc + aws/kinesis/core/test/test_utils.h + aws/kinesis/core/test/user_record_test.cc + aws/metrics/test/accumulator_test.cc + aws/metrics/test/metric_test.cc + aws/metrics/test/metrics_manager_test.cc + aws/auth/test/mutable_static_creds_provider_test.cc ) set(THIRD_PARTY_LIBS third_party/lib) diff --git a/aws/utils/spin_lock.cc b/aws/utils/spin_lock.cc index f8396c69..41f07f26 100644 --- a/aws/utils/spin_lock.cc +++ b/aws/utils/spin_lock.cc @@ -14,7 +14,7 @@ #include "spin_lock.h" using namespace aws::utils; - +#ifdef DEBUG namespace { thread_local TicketSpinLock::DebugStats debug_stats; } @@ -34,3 +34,4 @@ void TicketSpinLock::add_spin() { TicketSpinLock::DebugStats TicketSpinLock::get_debug_stats() { return debug_stats; } +#endif diff --git a/aws/utils/spin_lock.h b/aws/utils/spin_lock.h index 1a9a6e74..032aeee5 100644 --- a/aws/utils/spin_lock.h +++ b/aws/utils/spin_lock.h @@ -81,9 +81,9 @@ class TicketSpinLock : boost::noncopyable { inline std::condition_variable& cv_for_ticket(const std::size_t& ticket) noexcept { return unlocked_cv_[lock_shard(ticket)]; } - static const std::uint32_t kMaxSpinCount = 1000; + static const std::uint32_t kMaxSpinCount = 100; - static const std::size_t kLockShards = 13; + static const std::size_t kLockShards = 31; std::array condition_locks_; std::array unlocked_cv_; std::atomic now_serving_; diff --git a/aws/utils/test/spin_lock_test.cc b/aws/utils/test/spin_lock_test.cc index 3a0dbb4c..779d4dcd 100644 --- a/aws/utils/test/spin_lock_test.cc +++ b/aws/utils/test/spin_lock_test.cc @@ -87,11 +87,11 @@ void test(const std::string test_name, BOOST_AUTO_TEST_SUITE(SpinLock) -// BOOST_AUTO_TEST_CASE(SpinLock) { -// for (size_t i : {1, 4, 8}) { -// test("SpinLock", i); -// } -// } +BOOST_AUTO_TEST_CASE(SpinLock) { + for (size_t i : {1, 4, 8}) { + test("SpinLock", i); + } +} BOOST_AUTO_TEST_CASE(TicketSpinLock) { for (size_t i : {1, 4, 8, 16, 32}) { @@ -99,10 +99,10 @@ BOOST_AUTO_TEST_CASE(TicketSpinLock) { } } -// BOOST_AUTO_TEST_CASE(StdMutex) { -// for (size_t i : {1, 4, 8}) { -// test("std::mutex", i); -// } -// } +BOOST_AUTO_TEST_CASE(StdMutex) { + for (size_t i : {1, 4, 8}) { + test("std::mutex", i); + } +} BOOST_AUTO_TEST_SUITE_END() From b7af2c9532ccbb77ef5df8e5f8bda705748dcca8 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Thu, 22 Mar 2018 14:00:03 -0700 Subject: [PATCH 4/9] Update copyright statements --- aws/utils/spin_lock.h | 2 +- aws/utils/test/spin_lock_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/utils/spin_lock.h b/aws/utils/spin_lock.h index 032aeee5..cbb777a6 100644 --- a/aws/utils/spin_lock.h +++ b/aws/utils/spin_lock.h @@ -1,4 +1,4 @@ -// Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Amazon Software License (the "License"). // You may not use this file except in compliance with the License. diff --git a/aws/utils/test/spin_lock_test.cc b/aws/utils/test/spin_lock_test.cc index 779d4dcd..a6ce1c21 100644 --- a/aws/utils/test/spin_lock_test.cc +++ b/aws/utils/test/spin_lock_test.cc @@ -1,4 +1,4 @@ -// Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Amazon Software License (the "License"). // You may not use this file except in compliance with the License. From cf0932a8898685e0dc5a99b7e21aede408934fad Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Fri, 23 Mar 2018 07:20:05 -0700 Subject: [PATCH 5/9] Have the test run for 2 to 128 threads. --- aws/utils/test/concurrent_linked_queue_test.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aws/utils/test/concurrent_linked_queue_test.cc b/aws/utils/test/concurrent_linked_queue_test.cc index 6b7b7807..62742eef 100644 --- a/aws/utils/test/concurrent_linked_queue_test.cc +++ b/aws/utils/test/concurrent_linked_queue_test.cc @@ -152,9 +152,12 @@ BOOST_AUTO_TEST_CASE(Concurrent) { return end - start; }; + const std::size_t kThreadCount = 128; + for (size_t num_threads = 2; - num_threads < std::max(aws::thread::hardware_concurrency(), 8u); + num_threads < kThreadCount; num_threads *= 2) { + LOG(info) << "Starting ConcurrentLinkedQueue test for " << num_threads << " threads"; auto duration = f(num_threads); auto nanos = std::chrono::duration_cast(duration).count(); From 335f8d405a1eab98f736faef798d10f1ca945088 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Fri, 23 Mar 2018 08:00:45 -0700 Subject: [PATCH 6/9] Remove logging message --- aws/utils/test/concurrent_linked_queue_test.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/aws/utils/test/concurrent_linked_queue_test.cc b/aws/utils/test/concurrent_linked_queue_test.cc index 62742eef..2a21779d 100644 --- a/aws/utils/test/concurrent_linked_queue_test.cc +++ b/aws/utils/test/concurrent_linked_queue_test.cc @@ -157,7 +157,6 @@ BOOST_AUTO_TEST_CASE(Concurrent) { for (size_t num_threads = 2; num_threads < kThreadCount; num_threads *= 2) { - LOG(info) << "Starting ConcurrentLinkedQueue test for " << num_threads << " threads"; auto duration = f(num_threads); auto nanos = std::chrono::duration_cast(duration).count(); From 333ca233de0c61f133f6634fd115d63d014ff8f1 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Fri, 23 Mar 2018 08:01:18 -0700 Subject: [PATCH 7/9] Reduce the number of items used in the test --- aws/utils/test/concurrent_linked_queue_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/utils/test/concurrent_linked_queue_test.cc b/aws/utils/test/concurrent_linked_queue_test.cc index 2a21779d..6f658fe8 100644 --- a/aws/utils/test/concurrent_linked_queue_test.cc +++ b/aws/utils/test/concurrent_linked_queue_test.cc @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(Destructor) { } BOOST_AUTO_TEST_CASE(Concurrent) { - const size_t total_num_items = 1 << 22; + const size_t total_num_items = 1 << 20; auto f = [&](const size_t num_threads) { LOG(info) << "Starting concurrent queue test for " << num_threads From 600c717ac060deea35dc891b3b95c54d3fd9a8e6 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Fri, 23 Mar 2018 09:05:52 -0700 Subject: [PATCH 8/9] Advance to snapshot --- java/amazon-kinesis-producer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/amazon-kinesis-producer/pom.xml b/java/amazon-kinesis-producer/pom.xml index 9437ed12..07ef5551 100644 --- a/java/amazon-kinesis-producer/pom.xml +++ b/java/amazon-kinesis-producer/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.amazonaws amazon-kinesis-producer - 0.12.8 + 0.12.9-SNAPSHOT Amazon Kinesis Producer Library From f5162d8003265f818b345c218c1606eb722ce4e1 Mon Sep 17 00:00:00 2001 From: "Pfifer, Justin" Date: Fri, 6 Apr 2018 12:17:21 -0700 Subject: [PATCH 9/9] Added comments about condition variable usage Resolves comments on PR #193 --- aws/utils/spin_lock.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/aws/utils/spin_lock.h b/aws/utils/spin_lock.h index cbb777a6..041d10f0 100644 --- a/aws/utils/spin_lock.h +++ b/aws/utils/spin_lock.h @@ -56,7 +56,18 @@ class TicketSpinLock : boost::noncopyable { add_spin(); spin_count++; if (spin_count > kMaxSpinCount) { + // + // Condition variables in C++ are interesting. They require you take a lock before waiting on the variable. + // Once you start waiting the lock you originally took is released, which will allow the notifier to pick up + // the lock on the notification step. + // std::unique_lock lock(lock_for_ticket(my_ticket)); + // + // We start waiting on the curent lock holder to notify us that they have completed their work. + // When the lock holder triggers the notification the provided lambda is used to determine whether this + // thread should wake up, or instead re-enter the blocked state. This prevents us from needing to + // re-enter this blocked state explicitly. + // cv_for_ticket(my_ticket).wait(lock, [this, &my_ticket] { return now_serving_ == my_ticket; }); spin_count = 0; add_acquired_lock();