jaulib v1.5.0
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
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 <cstring>
26#include <thread>
27#include <pthread.h>
28
29#include <jau/test/catch2_ext.hpp>
30
31#include <jau/latch.hpp>
32
33using namespace jau;
34using namespace jau::fractions_i64_literals;
35using namespace jau::int_literals;
36
38 private:
39 jau::relaxed_atomic_int my_counter = 0;
40
41 void countDown(jau::latch& l, const fraction_i64 duration) {
42 my_counter--;
43 jau::sleep_for( duration );
44 l.count_down();
45 }
46
47 void countUp(jau::latch& l, const fraction_i64 duration) {
48 my_counter++;
49 jau::sleep_for( duration );
50 l.count_up();
51 }
52
53 public:
54
55 /**
56 * Testing jau::latch with set initial count value, count_down() and arrive_and_wait().
57 */
59 INFO_STR("\n\ntest01\n");
60 const size_t count = 10;
61 std::thread tasks[count];
62 jau::latch completion(count+1);
63
64 my_counter = count;
65
66 REQUIRE_EQUAL(count+1, completion.value());
67 REQUIRE_EQUAL(count, my_counter.load());
68
69 for(size_t i=0; i<count; i++) {
70 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
71 }
72 completion.arrive_and_wait();
73
74 REQUIRE(0 == completion.value());
75 REQUIRE(0 == my_counter);
76
77 for(auto & task : tasks) {
78 if( task.joinable() ) {
79 task.join();
80 }
81 }
82 }
83
84 /**
85 * Testing jau::latch with set initial count value, count_down() and arrive_and_wait_for().
86 */
88 INFO_STR("\n\ntest02\n");
89 const size_t count = 10;
90 std::thread tasks[count];
91 jau::latch completion(count+1);
92
93 my_counter = count;
94
95 REQUIRE_EQUAL(count+1, completion.value());
96 REQUIRE_EQUAL(count, my_counter.load());
97
98 for(size_t i=0; i<count; i++) {
99 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
100 }
101 REQUIRE( true == completion.arrive_and_wait_for(10_s) );
102
103 REQUIRE(0 == completion.value());
104 REQUIRE(0 == my_counter);
105
106 for(auto & task : tasks) {
107 if( task.joinable() ) {
108 task.join();
109 }
110 }
111 }
112
113 /**
114 * Testing jau::latch default ctor with zero value, then set initial count value, count_down() and wait_for().
115 */
117 INFO_STR("\n\ntest03\n");
118 const size_t count = 10;
119 std::thread tasks[count];
120 jau::latch completion;
121
122 REQUIRE( 0 == completion.value() );
123
124 my_counter = count;
125 completion.set(count);
126
127 REQUIRE_EQUAL(count, completion.value());
128 REQUIRE_EQUAL(count, my_counter.load());
129
130 for(size_t i=0; i<count; i++) {
131 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
132 }
133 REQUIRE( true == completion.wait_for(10_s) );
134
135 REQUIRE(0 == completion.value());
136 REQUIRE(0 == my_counter);
137
138 for(auto & task : tasks) {
139 if( task.joinable() ) {
140 task.join();
141 }
142 }
143 }
144
145
146 /**
147 * Testing jau::latch with zero initial count value, count_up(), count_down() and wait().
148 */
150 INFO_STR("\n\ntest04\n");
151 const size_t count = 10;
152 std::thread tasks[count];
153 jau::latch completion;
154
155 my_counter = 0;
156
157 REQUIRE( 0 == completion.value() );
158 REQUIRE( 0 == my_counter );
159
160 // count up
161 {
162 for(size_t i=0; i<count; i++) {
163 tasks[i] = std::thread(&TestLatch01::countUp, this, std::ref(completion), (int64_t)i*1_ms);
164 }
165
166 // TODO?: Add latch::wait_for_max()?
167 while( completion.value() < count ) {
168 jau::sleep_for( 10_ms );
169 }
170 REQUIRE_EQUAL(count, completion.value());
171 REQUIRE_EQUAL(count, my_counter.load());
172 for(auto & task : tasks) {
173 if( task.joinable() ) {
174 task.join();
175 }
176 }
177 }
178 // count down
179 {
180 for(size_t i=0; i<count; i++) {
181 tasks[i] = std::thread(&TestLatch01::countDown, this, std::ref(completion), (int64_t)i*1_ms);
182 }
183 REQUIRE(true == completion.wait_for(10_s) );
184
185 REQUIRE(0 == completion.value());
186 REQUIRE(0 == my_counter);
187
188 for(auto & task : tasks) {
189 if( task.joinable() ) {
190 task.join();
191 }
192 }
193 }
194 }
195};
196
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:192
size_t value() const noexcept
Return the current atomic internal counter.
Definition latch.hpp:93
void set(const size_t n) noexcept
Atomically set the internal counter by n.
Definition latch.hpp:153
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:209
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:240
ordered_atomic< int, std::memory_order_relaxed > relaxed_atomic_int
Relaxed non-SC atomic integral scalar integer.
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
__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")