C++ header-only library which provides CML-style events.
CML-style events allow the synchronization of values via channels.
Events are first-class values which are returned by non-blocking send and receive operations.
Only an explicit sync
call is blocking.
Channels can be closed which prevents any further send and receive operations.
The operations always return a flag which indicates whether the channel has already been closed (similar to Go).
The following example shows how a string value is synchronized between two threads using events:
#include <channel.hpp>
int main() {
events::Channel<std::string> c;
// Thread 1
std::thread t1([&c] {
auto e = c.sendEvt("Hello world!");
bool successful = e.sync();
if (!successful) {
std::cerr << "Channel has been closed." << std::endl;
}
});
// Thread 2
std::thread t2([&c] {
auto e = c.recvEvt();
std::optional<std::string> result = e.sync();
if (result.has_value()) {
std::cout << result.value();
} else {
std::cerr << "Channel has been closed." << std::endl;
}
});
t1.join();
t2.join();
return 0;
}
Events allow you to use more advanced combinators. The following example shows how we choose the first synchronized event from two different channels and wrap its result to a string which is printed to the standard output:
#include <channel.hpp>
int main() {
events::Channel<std::string> c1;
events::Channel<std::string> c2;
// Thread 1
std::thread t1([&c1] {
c1.sendEvt("A").sync();
});
// Thread 2
std::thread t2([&c2] {
c2.sendEvt("B").sync();
});
// Thread 3
std::thread t3([&c1, &c2] {
auto e1 = c1.recvEvt();
auto e2 = c2.recvEvt();
auto e3 = e1.choose(e2);
auto e4 = e3.wrap<std::string>([] (const std::optional<std::string> &v) {
if (v.has_value()) {
return "Result: " + v;
}
else {
return "Channel has been closed.";
}
});
std::cout << e4.sync() << std::endl;
});
t1.join();
t2.join();
t3.join();
return 0;
}
The current implementation is based on MVars.