Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4d797f1

Browse files
Move values (#71)
* Move values * Set release version * Use size of internal queue * Document known issues * Test with more std algorithms * Test writing on closed channel * Improve documentation
1 parent 8d0616c commit 4d797f1

File tree

8 files changed

+176
-59
lines changed

8 files changed

+176
-59
lines changed

‎CMakeLists.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.12)
22
project(cpp_channel)
3-
set(PROJECT_VERSION 1.2.0)
3+
set(PROJECT_VERSION 1.2.1)
44

55
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard")
66
set(CMAKE_CXX_STANDARD_REQUIRED YES)

‎README.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Channel
22

33
[![build](https://github.com/andreiavrammsd/cpp-channel/actions/workflows/cmake.yml/badge.svg)](https://github.com/andreiavrammsd/cpp-channel/actions) [![codecov](https://codecov.io/github/andreiavrammsd/cpp-channel/graph/badge.svg?token=CKQ0TVW62Z)](https://codecov.io/github/andreiavrammsd/cpp-channel)
4-
[![documentation](https://github.com/andreiavrammsd/cpp-channel/workflows/doc/badge.svg)](https://andreiavrammsd.github.io/cpp-channel/)
4+
[![documentation](https://github.com/andreiavrammsd/cpp-channel/actions/workflows/doc.yml/badge.svg)](https://andreiavrammsd.github.io/cpp-channel/)
55

66
### Thread-safe container for sharing data between threads (synchronized queue). Header-only. Compatible with C++11.
77

@@ -11,9 +11,10 @@
1111
* Blocking (forever waiting to fetch).
1212
* Range-based for loop supported.
1313
* Close to prevent pushing and stop waiting to fetch.
14-
* Integrates well with STL algorithms in some cases. Eg:
14+
* Integrates with some of the STD algorithms. Eg:
1515
* `std::move(ch.begin(), ch.end(), ...)`
1616
* `std::transform(input_chan.begin(), input_chan.end(), msd::back_inserter(output_chan))`.
17+
* `std::copy_if(chan.begin(), chan.end(), ...);`
1718
* Tested with GCC, Clang, and MSVC.
1819
* Includes stack-based, exception-free alternative (static channel).
1920

@@ -136,6 +137,10 @@ int main() {
136137

137138
See [examples](https://github.com/andreiavrammsd/cpp-channel/tree/master/examples) and [documentation](https://andreiavrammsd.github.io/cpp-channel/).
138139

140+
## Known limitations
141+
142+
* In some cases, the integration with some STD algorithms does not compile with MSVC. See the [Transform test](https://github.com/andreiavrammsd/cpp-channel/blob/master/tests/channel_test.cpp).
143+
139144
<br>
140145

141146
Developed with [CLion](https://www.jetbrains.com/?from=serializer) and [Visual Studio Code](https://code.visualstudio.com/).

‎examples/multithreading.cpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <cstdint>
22
#include <cstdlib>
33
#include <iostream>
4+
#include <sstream>
45
#include <thread>
56
#include <utility>
67

@@ -15,7 +16,9 @@ int main()
1516
// Read
1617
const auto out = [](msd::channel<std::int64_t>& ch, std::size_t i) {
1718
for (auto number : ch) {
18-
std::cout << number << " from thread: " << i << '\n';
19+
std::stringstream stream;
20+
stream << number << " from thread: " << i << '\n';
21+
std::cout << stream.str();
1922
std::this_thread::sleep_for(std::chrono::milliseconds(500));
2023
}
2124
};

‎include/msd/blocking_iterator.hpp‎

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
namespace msd {
1010

1111
/**
12-
* @brief An iterator that block the current thread, waiting to fetch elements from the channel.
12+
* @brief An iterator that blocks the current thread, waiting to fetch elements from the channel.
1313
*
14-
* Used to implement channel range-based for loop.
14+
* @details Used to implement channel range-based for loop.
1515
*
1616
* @tparam Channel Type of channel being iterated.
1717
*/
@@ -61,7 +61,7 @@ class blocking_iterator {
6161
*
6262
* @return The iterator itself.
6363
*/
64-
blocking_iterator<Channel> operator++() noexcept
64+
blocking_iterator<Channel>& operator++() noexcept
6565
{
6666
if (!chan_->read(value_)) {
6767
is_end_ = true;
@@ -80,7 +80,6 @@ class blocking_iterator {
8080
* @brief Makes iteration continue until the channel is closed and empty.
8181
*
8282
* @param other Another blocking_iterator to compare with.
83-
*
8483
* @return true if the channel is not closed or not empty (continue iterating).
8584
* @return false if the channel is closed and empty (stop iterating).
8685
*/
@@ -95,7 +94,7 @@ class blocking_iterator {
9594
/**
9695
* @brief An output iterator pushes elements into a channel. Blocking until the channel is not full.
9796
*
98-
* Used to integrate with standard algorithms that require an output iterator.
97+
* @details Used to integrate with standard algorithms that require an output iterator.
9998
*
10099
* @tparam Channel Type of channel being iterated.
101100
*/
@@ -137,20 +136,25 @@ class blocking_writer_iterator {
137136
/**
138137
* @brief Writes an element into the channel, blocking until space is available.
139138
*
140-
* @param val The value to be written into the channel.
141-
*
139+
* @param value The value to be written into the channel.
142140
* @return The iterator itself.
141+
* @note There is no effect if the channel is closed.
143142
*/
144-
blocking_writer_iterator& operator=(const value_type& val)
143+
blocking_writer_iterator& operator=(reference value)
145144
{
146-
chan_->write(val);
145+
chan_->write(value);
147146
return *this;
148147
}
149148

150149
/**
151150
* @brief Not applicable (handled by operator=).
152151
*
153152
* @return The iterator itself.
153+
*
154+
* @note It's uncommon to return a reference to an iterator, but I don't want to return a value from the channel.
155+
* This iterator is supposed to be used only to write values.
156+
* I don't know if it's a terrible idea or not, but it looks related to the issue with MSVC
157+
* in the Transform test in tests/channel_test.cpp.
154158
*/
155159
blocking_writer_iterator& operator*() { return *this; }
156160

@@ -176,9 +180,7 @@ class blocking_writer_iterator {
176180
* @brief Creates a blocking iterator for the given channel.
177181
*
178182
* @tparam Channel Type of channel being iterated.
179-
*
180183
* @param chan Reference to the channel this iterator will iterate over.
181-
*
182184
* @return A blocking iterator for the specified channel.
183185
*/
184186
template <typename Channel>

‎include/msd/channel.hpp‎

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class closed_channel : public std::runtime_error {
3131
/**
3232
* @brief Thread-safe container for sharing data between threads.
3333
*
34-
* Implements a blocking input iterator.
34+
* - Not movable, not copyable.
35+
* - Includes a blocking input iterator.
3536
*
3637
* @tparam T The type of the elements.
3738
*/
@@ -85,9 +86,7 @@ class channel {
8586
* @brief Pushes an element into the channel.
8687
*
8788
* @tparam Type The type of the elements.
88-
*
8989
* @param value The element to be pushed into the channel.
90-
*
9190
* @return true If an element was successfully pushed into the channel.
9291
* @return false If the channel is closed.
9392
*/
@@ -103,7 +102,6 @@ class channel {
103102
}
104103

105104
queue_.push(std::forward<Type>(value));
106-
++size_;
107105
}
108106

109107
cnd_.notify_one();
@@ -115,7 +113,6 @@ class channel {
115113
* @brief Pops an element from the channel.
116114
*
117115
* @param out Reference to the variable where the popped element will be stored.
118-
*
119116
* @return true If an element was successfully read from the channel.
120117
* @return false If the channel is closed and empty.
121118
*/
@@ -125,13 +122,12 @@ class channel {
125122
std::unique_lock<std::mutex> lock{mtx_};
126123
waitBeforeRead(lock);
127124

128-
if (is_closed_ && size_ == 0) {
125+
if (is_closed_ && queue_.empty()) {
129126
return false;
130127
}
131128

132129
out = std::move(queue_.front());
133130
queue_.pop();
134-
--size_;
135131
}
136132

137133
cnd_.notify_one();
@@ -147,7 +143,7 @@ class channel {
147143
NODISCARD size_type size() const noexcept
148144
{
149145
std::unique_lock<std::mutex> lock{mtx_};
150-
return size_;
146+
return queue_.size();
151147
}
152148

153149
/**
@@ -159,7 +155,7 @@ class channel {
159155
NODISCARD bool empty() const noexcept
160156
{
161157
std::unique_lock<std::mutex> lock{mtx_};
162-
return size_ == 0;
158+
return queue_.empty();
163159
}
164160

165161
/**
@@ -195,7 +191,7 @@ class channel {
195191
NODISCARD bool drained() noexcept
196192
{
197193
std::unique_lock<std::mutex> lock{mtx_};
198-
return size_ == 0 && is_closed_;
194+
return queue_.empty() && is_closed_;
199195
}
200196

201197
/**
@@ -212,9 +208,6 @@ class channel {
212208
*/
213209
iterator end() noexcept { return blocking_iterator<channel<T>>{*this, true}; }
214210

215-
/**
216-
* Channel cannot be copied or moved.
217-
*/
218211
channel(const channel&) = delete;
219212
channel& operator=(const channel&) = delete;
220213
channel(channel&&) = delete;
@@ -223,21 +216,20 @@ class channel {
223216

224217
private:
225218
std::queue<T> queue_;
226-
std::size_t size_{0};
227219
const size_type cap_{0};
228220
mutable std::mutex mtx_;
229221
std::condition_variable cnd_;
230222
bool is_closed_{false};
231223

232224
void waitBeforeRead(std::unique_lock<std::mutex>& lock)
233225
{
234-
cnd_.wait(lock, [this]() { return size_ > 0 || is_closed_; });
226+
cnd_.wait(lock, [this]() { return !queue_.empty() || is_closed_; });
235227
};
236228

237229
void waitBeforeWrite(std::unique_lock<std::mutex>& lock)
238230
{
239-
if (cap_ > 0 && size_ == cap_) {
240-
cnd_.wait(lock, [this]() { return size_ < cap_; });
231+
if (cap_ > 0 && queue_.size() == cap_) {
232+
cnd_.wait(lock, [this]() { return queue_.size() < cap_; });
241233
}
242234
}
243235
};

‎include/msd/static_channel.hpp‎

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ namespace msd {
1616
/**
1717
* @brief Thread-safe container for sharing data between threads.
1818
*
19-
* Allocates elements on the stack.
20-
* Does not throw exceptions.
21-
* Implements a blocking input iterator.
19+
* - Allocates elements on the stack.
20+
* - Does not throw exceptions.
21+
* - Not movable, not copyable.
22+
* - Includes a blocking input iterator.
2223
*
2324
* @tparam T The type of the elements.
2425
* @tparam Capacity The maximum number of elements the channel can hold before blocking.
@@ -52,9 +53,7 @@ class static_channel {
5253
* @brief Pushes an element into the channel.
5354
*
5455
* @tparam Type The type of the elements.
55-
*
5656
* @param value The element to be pushed into the channel.
57-
*
5857
* @return true If an element was successfully pushed into the channel.
5958
* @return false If the channel is closed.
6059
*/
@@ -82,7 +81,6 @@ class static_channel {
8281
* @brief Pops an element from the channel.
8382
*
8483
* @param out Reference to the variable where the popped element will be stored.
85-
*
8684
* @return true If an element was successfully read from the channel.
8785
* @return false If the channel is closed and empty.
8886
*/
@@ -179,9 +177,6 @@ class static_channel {
179177
*/
180178
iterator end() noexcept { return blocking_iterator<static_channel<T, Capacity>>{*this, true}; }
181179

182-
/**
183-
* Channel cannot be copied or moved.
184-
*/
185180
static_channel(const static_channel&) = delete;
186181
static_channel& operator=(const static_channel&) = delete;
187182
static_channel(static_channel&&) = delete;

‎tests/blocking_iterator_test.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ TEST(BlockingWriterIteratorTest, WriteToChannelUsingBackInserter)
7070
*out = 20;
7171
*out = 30;
7272
channel.close();
73+
*out = 40; // Ignored because the channel is closed
7374
});
7475

7576
std::vector<int> results;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /