jaulib v1.3.0
Jau Support Library (C++, Java, ..)
test_latch01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24#include <cassert>
25#include <cinttypes>
26#include <cstring>
27#include <memory>
28#include <thread>
29#include <pthread.h>
30
32
33#include <jau/latch.hpp>
34
35using namespace jau;
36using namespace jau::fractions_i64_literals;
37using namespace jau::int_literals;
38
40 private:
41 jau::relaxed_atomic_int my_counter = 0;
42
43 void countDown(jau::latch& l, const fraction_i64 duration) {
44 my_counter--;
45 jau::sleep_for( duration );
46 l.count_down();
47 }
48
49 void countUp(jau::latch& l, const fraction_i64 duration) {
50 my_counter++;
51 jau::sleep_for( duration );
52 l.count_up();
53 }
54
55 public:
56
57 /**
58 * Testing jau::latch with set initial count value, count_down() and arrive_and_wait().
59 */
61 INFO_STR("\n\ntest01\n");
62 const size_t count = 10;
63 std::thread tasks[count];
64 jau::latch completion(count+1);
65
66 my_counter = count;
67
68 REQUIRE(count+1 == completion.value());
69 REQUIRE(count == my_counter);
70
71 for(size_t i=0; i<count; i++) {
72 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
73 }
74 completion.arrive_and_wait();
75
76 REQUIRE(0 == completion.value());
77 REQUIRE(0 == my_counter);
78
79 for(auto & task : tasks) {
80 if( task.joinable() ) {
81 task.join();
82 }
83 }
84 }
85
86 /**
87 * Testing jau::latch with set initial count value, count_down() and arrive_and_wait_for().
88 */
90 INFO_STR("\n\ntest02\n");
91 const size_t count = 10;
92 std::thread tasks[count];
93 jau::latch completion(count+1);
94
95 my_counter = count;
96
97 REQUIRE(count+1 == completion.value());
98 REQUIRE(count == my_counter);
99
100 for(size_t i=0; i<count; i++) {
101 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
102 }
103 REQUIRE( true == completion.arrive_and_wait_for(10_s) );
104
105 REQUIRE(0 == completion.value());
106 REQUIRE(0 == my_counter);
107
108 for(auto & task : tasks) {
109 if( task.joinable() ) {
110 task.join();
111 }
112 }
113 }
114
115 /**
116 * Testing jau::latch default ctor with zero value, then set initial count value, count_down() and wait_for().
117 */
119 INFO_STR("\n\ntest03\n");
120 const size_t count = 10;
121 std::thread tasks[count];
122 jau::latch completion;
123
124 REQUIRE( 0 == completion.value() );
125
126 my_counter = count;
127 completion.set(count);
128
129 REQUIRE(count == completion.value());
130 REQUIRE(count == my_counter);
131
132 for(size_t i=0; i<count; i++) {
133 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
134 }
135 REQUIRE( true == completion.wait_for(10_s) );
136
137 REQUIRE(0 == completion.value());
138 REQUIRE(0 == my_counter);
139
140 for(auto & task : tasks) {
141 if( task.joinable() ) {
142 task.join();
143 }
144 }
145 }
146
147
148 /**
149 * Testing jau::latch with zero initial count value, count_up(), count_down() and wait().
150 */
152 INFO_STR("\n\ntest04\n");
153 const size_t count = 10;
154 std::thread tasks[count];
155 jau::latch completion;
156
157 my_counter = 0;
158
159 REQUIRE( 0 == completion.value() );
160 REQUIRE( 0 == my_counter );
161
162 // count up
163 {
164 for(size_t i=0; i<count; i++) {
165 tasks[i] = std::thread(&TestLatch01::countUp, this, std::ref(completion), (int64_t)i*1_ms);
166 }
167
168 // TODO?: Add latch::wait_for_max()?
169 while( completion.value() < count ) {
170 jau::sleep_for( 10_ms );
171 }
172 REQUIRE(count == completion.value());
173 REQUIRE(count == my_counter);
174 for(auto & task : tasks) {
175 if( task.joinable() ) {
176 task.join();
177 }
178 }
179 }
180 // count down
181 {
182 for(size_t i=0; i<count; i++) {
183 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
184 }
185 REQUIRE(true == completion.wait_for(10_s) );
186
187 REQUIRE(0 == completion.value());
188 REQUIRE(0 == my_counter);
189
190 for(auto & task : tasks) {
191 if( task.joinable() ) {
192 task.join();
193 }
194 }
195 }
196 }
197};
198
#define INFO_STR(msg)
Definition: catch2_ext.hpp:75
void test04_up_wait_for()
Testing jau::latch with zero initial count value, count_up(), count_down() and wait().
void test02_down_wait_for()
Testing jau::latch with set initial count value, count_down() and arrive_and_wait_for().
void test03_down_wait_for()
Testing jau::latch default ctor with zero value, then set initial count value, count_down() and wait_...
void test01_down_wait()
Testing jau::latch with set initial count value, count_down() and arrive_and_wait().
Inspired by std::latch of C++20.
Definition: latch.hpp:50
void arrive_and_wait(const size_t n=1) noexcept
Atomically decrements the internal counter by n and (if necessary) blocks the calling thread until th...
Definition: latch.hpp:193
size_t value() const noexcept
Return the current atomic internal counter.
Definition: latch.hpp:94
void set(const size_t n) noexcept
Atomically set the internal counter by n.
Definition: latch.hpp:154
bool wait_for(const fraction_i64 &timeout_duration) const noexcept
Blocks the calling thread until the internal counter reaches 0 or the given timeout duration has expi...
Definition: latch.hpp:210
void count_down(const size_t n=1) noexcept
Atomically decrements the internal counter by n and notifies all blocked wait() threads if zero is re...
Definition: latch.hpp:108
bool arrive_and_wait_for(const fraction_i64 &timeout_duration, const size_t n=1) noexcept
Atomically decrements the internal counter by n and (if necessary) blocks the calling thread until th...
Definition: latch.hpp:241
void count_up(const size_t n=1) noexcept
Atomically increments the internal counter by n, i.e.
Definition: latch.hpp:136
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
METHOD_AS_TEST_CASE(TestLatch01::test01_down_wait, "test01_down_wait")