LeechCraft 0.6.70-18808-g3467692359
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
corochanneltest.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#include "corochanneltest.h"
10#include <QtConcurrentRun>
11#include <QtTest>
12#include "coro.h"
13#include "coro/channel.h"
14#include "coro/channelutils.h"
15#include "coro/getresult.h"
16#include "coro/threadsafety.h"
17
18QTEST_GUILESS_MAIN (LC::Util::CoroChannelTest)
19
20namespace LC::Util
21{
22 void CoroChannelTest::testSingleRecv ()
23 {
24 using namespace std::chrono_literals;
25
26 constexpr auto producersCount = 32;
27 constexpr auto repCount = 100;
28 constexpr auto sleepLength = 1ms;
29
30 Channel<int> ch { this };
31
32 std::vector<std::thread> threads;
33 std::atomic_int expected;
34 for (int i = 0; i < producersCount; ++i)
35 threads.emplace_back ([&, i]
36 {
37 for (int j = 0; j < repCount; ++j)
38 {
39 const auto val = j * producersCount + i;
40 ch.Send (val);
41 expected.fetch_add (val, std::memory_order::relaxed);
42 std::this_thread::sleep_for (sleepLength);
43 }
44 });
45
46 auto mainThread = std::this_thread::get_id ();
47 auto reader = [] (auto mainThread, Channel<int> *ch) -> Task<int, ThreadSafetyExtension>
48 {
49 int sum = 0;
50 while (auto next = co_await ch->Receive ())
51 {
52 [=]
53 {
54 auto thisThread = std::this_thread::get_id ();
55 QCOMPARE (thisThread, mainThread);
56 } ();
57
58 sum += *next;
59 }
60 co_return sum;
61 } (mainThread, &ch);
62
63 for (auto& thread : threads)
64 thread.join ();
65
66 ch.Close ();
67
68 auto result = GetTaskResult (reader);
69 QCOMPARE (result, expected);
70 }
71
72 void CoroChannelTest::testManyRecvs ()
73 {
74 using namespace std::chrono_literals;
75
76 constexpr auto producersCount = 32;
77 constexpr auto consumersCount = 8;
78 constexpr auto repCount = 100;
79 constexpr auto sleepLength = 1ms;
80
81 Channel<int> ch;
82
83 std::vector<std::thread> producers;
84 std::atomic_int expected;
85 for (int i = 0; i < producersCount; ++i)
86 producers.emplace_back ([&, i]
87 {
88 for (int j = 0; j < repCount; ++j)
89 {
90 const auto val = j * producersCount + i;
91 ch.Send (val);
92 expected.fetch_add (val, std::memory_order::relaxed);
93 std::this_thread::sleep_for (sleepLength);
94 }
95 });
96
97 std::atomic_int sum;
98 std::vector<std::thread> consumers;
99 for (int i = 0; i < consumersCount; ++i)
100 consumers.emplace_back ([&]
101 {
102 auto reader = [] (Channel<int> *ch) -> Task<int, ThreadSafetyExtension>
103 {
104 int sum = 0;
105 while (auto next = co_await ch->Receive ())
106 sum += *next;
107 co_return sum;
108 } (&ch);
109 sum.fetch_add (GetTaskResult (reader));
110 });
111
112 for (auto& thread : producers)
113 thread.join ();
114
115 ch.Close ();
116
117 for (auto& thread : consumers)
118 thread.join ();
119
120 QCOMPARE (sum, expected);
121 }
122
123 void CoroChannelTest::testSingleThreaded ()
124 {
125 constexpr auto iterations = 1000;
126
127 Channel<int> ch;
128
129 auto reader = [] (Channel<int> *ch) -> Task<int, ThreadSafetyExtension>
130 {
131 int sum = 0;
132 while (auto next = co_await ch->Receive ())
133 sum += *next;
134 co_return sum;
135 } (&ch);
136
137 int expected = 0;
138 for (int i = 0; i < iterations; ++i)
139 {
140 expected += i;
141 ch.Send (i);
142 }
143
144 ch.Close ();
145
146 const auto result = GetTaskResult (reader);
147 QCOMPARE (result, expected);
148 }
149
150 void CoroChannelTest::testSingleThreadedTimered ()
151 {
152 using namespace std::chrono_literals;
153
154 constexpr auto iterations = 100;
155 constexpr auto interval = 1ms;
156
157 Channel<int> ch;
158
159 auto reader = [] (Channel<int> *ch) -> Task<int, ThreadSafetyExtension>
160 {
161 int sum = 0;
162 while (auto next = co_await ch->Receive ())
163 sum += *next;
164 co_return sum;
165 } (&ch);
166
167 int expected = 0;
168
169 QTimer timer;
170 timer.callOnTimeout ([&, i = 0] mutable
171 {
172 expected += i;
173 ch.Send (i);
174 if (++i == iterations)
175 {
176 timer.stop ();
177 ch.Close ();
178 }
179 });
180 timer.start (interval);
181
182 const auto result = GetTaskResult (reader);
183 QCOMPARE (result, expected);
184 }
185
186 void CoroChannelTest::testMerge ()
187 {
188 using namespace std::chrono_literals;
189
190 constexpr auto numChannels = 100;
191 constexpr auto iterations = 100;
192 constexpr auto interval = 1ms;
193
194 QVector<Channel_ptr<int>> channels;
195 std::generate_n (std::back_inserter (channels), numChannels, [] { return std::make_shared<Channel<int>> (); });
196
197 auto merged = MergeChannels (channels);
198
199 auto reader = [] (Channel<int> *ch) -> Task<int, ThreadSafetyExtension>
200 {
201 int sum = 0;
202 while (auto next = co_await ch->Receive ())
203 sum += *next;
204 co_return sum;
205 } (merged.get ());
206
207 int expected = 0;
208
209 QTimer timer;
210 timer.callOnTimeout ([&, i = 0] mutable
211 {
212 for (int j = 0; j < numChannels; ++j)
213 {
214 auto value = i * numChannels + j;
215 expected += value;
216 channels [j]->Send (value);
217 }
218 if (++i == iterations)
219 {
220 timer.stop ();
221 for (auto chan : channels)
222 chan->Close ();
223 }
224 });
225 timer.start (interval);
226
227 const auto result = GetTaskResult (reader);
228 QCOMPARE (result, expected);
229 }
230}
T GetTaskResult(Task< T, Extensions... > task)
Definition getresult.h:19
Channel_ptr< T > MergeChannels(QVector< Channel_ptr< T > > channels)