aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-05-15 02:42:12 +0200
committerSven Gothel <[email protected]>2022-05-15 02:42:12 +0200
commit5c9bdab204224225da317b2025f61af6c15e1bab (patch)
treef3c500c5b7200dcc84c2ab6c66408063cbfe59f7
parent231e8dc311a28eccb7f04a2f355e59bcc2a9ac3e (diff)
jau::latch: Extend functionality with count_up(), allowing to dynamically add *events* to required to complete
-rw-r--r--include/jau/latch.hpp22
-rw-r--r--test/test_latch01.cpp56
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");