diff options
author | Sven Gothel <[email protected]> | 2022-05-15 02:42:12 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-05-15 02:42:12 +0200 |
commit | 5c9bdab204224225da317b2025f61af6c15e1bab (patch) | |
tree | f3c500c5b7200dcc84c2ab6c66408063cbfe59f7 | |
parent | 231e8dc311a28eccb7f04a2f355e59bcc2a9ac3e (diff) |
jau::latch: Extend functionality with count_up(), allowing to dynamically add *events* to required to complete
-rw-r--r-- | include/jau/latch.hpp | 22 | ||||
-rw-r--r-- | test/test_latch01.cpp | 56 |
2 files changed, 71 insertions, 7 deletions
diff --git a/include/jau/latch.hpp b/include/jau/latch.hpp index 6b01a1c..9cbfca8 100644 --- a/include/jau/latch.hpp +++ b/include/jau/latch.hpp @@ -43,6 +43,8 @@ namespace jau { /** * Inspired by std::latch of C++20 * + * Adds count_up() as an extension, allowing to dynamically add *events* to required to complete. + * * @see https://en.cppreference.com/w/cpp/thread/latch */ class latch { @@ -111,6 +113,26 @@ namespace jau { } /** + * Atomically increments the internal counter by n. + * + * If internal counter + n is greater than the maximum value of the internal counter, the counter is set to its maximum. + * + * This operation strongly happens-before all calls that are unblocked on this latch. + * + * Extension of std::latch. + * + * @param n the value by which the internal counter is increased, defaults to 1 + */ + void count_up(const size_t n = 1) noexcept { + std::unique_lock<std::mutex> lock(mtx_cd); // Avoid data-race on concurrent count_down() and wait*() calls + if( n <= std::numeric_limits<std::size_t>::max() - count ) { + count = count + n; + } else { + count = std::numeric_limits<std::size_t>::max(); + } + } + + /** * Returns true only if the internal counter has reached zero. * * Compatible with std::latch. diff --git a/test/test_latch01.cpp b/test/test_latch01.cpp index 66b2338..d627637 100644 --- a/test/test_latch01.cpp +++ b/test/test_latch01.cpp @@ -44,28 +44,39 @@ class TestLatch01 { private: jau::relaxed_atomic_int my_counter = 0; - void something(jau::latch& l) { + void something(jau::latch& l, const fraction_i64 duration) { my_counter++; + jau::sleep_for( duration ); + l.count_down(); + } + + void somethingUp(jau::latch& l, const fraction_i64 duration) { + l.count_up(); + my_counter++; + jau::sleep_for( duration ); l.count_down(); } public: + /** + * Testing jau::latch with set initial count value, count_down() and arrive_and_wait(). + */ void test01_wait() { INFO_STR("\n\ntest01\n"); - const size_t count = 8; + const size_t count = 10; std::thread tasks[count]; jau::latch completion(count+1); REQUIRE_MSG("not-zero", count+1 == completion.value()); for(size_t i=0; i<count; i++) { - tasks[i] = std::thread(&TestLatch01::something, this, std::ref(completion)); + tasks[i] = std::thread(&TestLatch01::something, this, std::ref(completion), (int64_t)i*1_ms); } completion.arrive_and_wait(); REQUIRE_MSG("zero", 0 == completion.value()); - REQUIRE_MSG("8", count == my_counter); + REQUIRE_MSG("10", count == my_counter); for(size_t i=0; i<count; i++) { if( tasks[i].joinable() ) { @@ -74,21 +85,51 @@ class TestLatch01 { } } + /** + * Testing jau::latch with set initial count value, count_down() and arrive_and_wait_for(). + */ void test02_wait_for() { INFO_STR("\n\ntest02\n"); - const size_t count = 8; + const size_t count = 10; std::thread tasks[count]; jau::latch completion(count+1); REQUIRE_MSG("not-zero", count+1 == completion.value()); for(size_t i=0; i<count; i++) { - tasks[i] = std::thread(&TestLatch01::something, this, std::ref(completion)); + tasks[i] = std::thread(&TestLatch01::something, this, std::ref(completion), (int64_t)i*1_ms); } REQUIRE_MSG("complete", true == completion.arrive_and_wait_for(10_s) ); REQUIRE_MSG("zero", 0 == completion.value()); - REQUIRE_MSG("8", count == my_counter); + REQUIRE_MSG("10", count == my_counter); + + for(size_t i=0; i<count; i++) { + if( tasks[i].joinable() ) { + tasks[i].join(); + } + } + } + + /** + * Testing jau::latch with zero initial count value, count_up(), count_down() and wait(). + */ + void test02_wait() { + INFO_STR("\n\ntest02\n"); + const size_t count = 10; + std::thread tasks[count]; + jau::latch completion(0); + + REQUIRE_MSG("not-zero", 0 == completion.value()); + + for(size_t i=0; i<count; i++) { + tasks[i] = std::thread(&TestLatch01::somethingUp, this, std::ref(completion), (int64_t)i*1_ms); + } + REQUIRE_MSG("not-zero", 0 < completion.value()); // at least one count_up() occurred + completion.wait(); + + REQUIRE_MSG("zero", 0 == completion.value()); + REQUIRE_MSG("10", count == my_counter); for(size_t i=0; i<count; i++) { if( tasks[i].joinable() ) { @@ -100,4 +141,5 @@ class TestLatch01 { METHOD_AS_TEST_CASE( TestLatch01::test01_wait, "Test TestLatch01 - test01_wait"); METHOD_AS_TEST_CASE( TestLatch01::test02_wait_for, "Test TestLatch01 - test02_wait_for"); +METHOD_AS_TEST_CASE( TestLatch01::test02_wait, "Test TestLatch01 - test02_wait"); |