Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Example Greenthreads | 278 | 10 months ago | 4 | mit | Rust | |||||
Repository accompanying article and gibook | ||||||||||
Fibry | 197 | 2 months ago | 37 | March 06, 2022 | mit | Java | ||||
The first Java Actor System supporting fibers from Project Loom | ||||||||||
Boson | 152 | 5 years ago | 1 | mit | C++ | |||||
A C++14 framework for asynchronous I/O, cooperative multitasking and green threads scheduling | ||||||||||
Gthreads | 149 | 6 years ago | 1 | C | ||||||
Toy Green Threads for C. | ||||||||||
Libwire | 145 | 5 years ago | 1 | mit | C | |||||
User space threading (aka coroutines) library for C resembling GoLang and goroutines | ||||||||||
Mioco | 122 | 4 years ago | 4 | Rust | ||||||
[no longer maintained] Scalable, coroutine-based, fibers/green-threads for Rust. (aka MIO COroutines). | ||||||||||
Conpig | 107 | 10 years ago | other | Python | ||||||
A green threading library with automated concurrency for python based on a processes, signal handlers and greenlets | ||||||||||
Book Green Threads Explained | 89 | 9 months ago | 7 | |||||||
Repository for the Green Threads Explained Book | ||||||||||
Gthreads Art | 46 | 6 years ago | 1 | HTML | ||||||
A green threads tutorial. | ||||||||||
Green_threads | 35 | 9 years ago | C++ | |||||||
C++ Green threads and coroutines library |
The Boson Framework is a C++ library to write concurrent software in C++. The framework inspires freely from what the Go language did to address complexity in concurrent programming. The Boson Framework implements features similar to three of Go's:
This project is currently a proof of concept. New features and performance improvements are to be expected in the near future.
The Boson Framework only supports Linux on x86-64 platforms for now, but Windows and Mac OS are in the roadmap.
The main point is to simplify writing concurrent applications by removing the asynchronous logic from the developer's mind. The developer only uses blocking calls, and the whole logic is written sequentially. Under the hood, blocking calls are not blocking from the OS standpoint, since the thread is still used to execute some tasks. This is different from using multiple threads because:
C
and Go
developers used to system interfaces.select_*
statement is versatile and allows programming constructs that are hard to reproduce without it.LD_PRELOAD
trick.The goal of the framework is to use light routines instead of threads. In Go, these are called Goroutines. In the C++ world, it is known as fibers. In the boson framework, we just call them routines.
This snippet just launches a simple routine that exits immediately.
boson::run(1 /* number of thread */, []() {
std::cout << "Hello world" << std::endl;
});
The boson framework provides its versions of system calls that are scheduled away for efficiency with an event loop. Current asynchronized syscalls are:
sleep
, usleep
, nanosleep
read
, recv
write
, send
accept
connect
See an example.
This snippet launches two routines doing different jobs, in a single thread.
void timer(int out, bool& stopper) {
while(!stopper) {
boson::sleep(1000ms);
boson::write(out,"Tick !\n",7);
}
boson::write(out,"Stop !\n",7);
}
void user_input(int in, bool& stopper) {
char buffer[1];
boson::read(in, &buffer, sizeof(buffer));
stopper = true;
}
int main(int argc, char *argv[]) {
bool stopper = false;
boson::run(1, [&stopper]() {
boson::start(timer, 1, stopper);
::fcntl(0, F_SETFL, ::fcntl(0, F_GETFD) | O_NONBLOCK);
boson::start(user_input, 0, stopper);
});
}
This executable prints Tick !
every second and quits if the user enters anything on the standard input. We dont have to manage concurrency on the stopper
variable since we know only one thread uses it. Plus, we know at which points the routines might be interrupted.
The boson framework implements channels similar to Go ones. Channels are used to communicate between routines. They can be used over multiple threads.
This snippet listens to the standard input in one thread and writes to two different files in two other threads. A channel is used to communicate. This also demonstrates the use of a generic lambda and a generic functor. Boson system calls are not used on the files because files on disk cannot be polled for events (not allowed by the Linux kernel).
struct writer {
template <class Channel>
void operator()(Channel input, char const* filename) const {
std::ofstream file(filename);
if (file) {
std::string buffer;
while(input >> buffer)
file << buffer << std::flush;
}
}
};
int main(int argc, char *argv[]) {
boson::run(3, []() {
boson::channel<std::string, 1> pipe;
// Listen stdin
boson::start_explicit(0, [](int in, auto output) -> void {
char buffer[2048];
ssize_t nread = 0;
while(0 < (nread = ::read(in, &buffer, sizeof(buffer)))) {
output << std::string(buffer,nread);
std::cout << "iter" << std::endl;
}
output.close();
}, 0, pipe);
// Output in files
writer functor;
boson::start_explicit(1, functor, pipe, "file1.txt");
boson::start_explicit(2, functor, pipe, "file2.txt");
});
}
Channels must be transfered by copy. Generic lambdas, when used as a routine seed, must explicitely state that they return void
. The why will be explained in detail in further documentation. Threads are assigned to routines in a round-robin fashion. The thread id can be explicitely given when starting a routine.
boson::start_explicit(0, [](int in, auto output) -> void {...}, 0, pipe);
boson::start_explicit(1, functor, pipe, "file1.txt");
boson::start_explicit(2, functor, pipe, "file2.txt");
See an example.
The select statement is similar to the Go one, but with a nice twist : it can be used with any blocking facility. That means you can mix channels, i/o events, mutex locks and timers in a single select_*
call.
// Create a pipe
int pipe_fds[2];
::pipe(pipe_fds);
::fcntl(pipe_fds[0], F_SETFL, ::fcntl(pipe_fds[0], F_GETFD) | O_NONBLOCK);
::fcntl(pipe_fds[1], F_SETFL, ::fcntl(pipe_fds[1], F_GETFD) | O_NONBLOCK);
boson::run(1, [&]() {
using namespace boson;
// Create channel
channel<int, 3> chan;
// Create mutex and lock it immediately
boson::mutex mut;
mut.lock();
// Start a producer
start([](int out, auto chan) -> void {
int data = 1;
boson::write(out, &data, sizeof(data));
chan << data;
}, pipe_fds[1], chan);
// Start a consumer
start([](int in, auto chan, auto mut) -> void {
int buffer = 0;
bool stop = false;
while (!stop) {
select_any( //
event_read(in, &buffer, sizeof(buffer),
[](ssize_t rc) { //
std::cout << "Got data from the pipe \n";
}),
event_read(chan, buffer,
[](bool) { //
std::cout << "Got data from the channel \n";
}),
event_lock(mut,
[]() { //
std::cout << "Got lock on the mutex \n";
}),
event_timer(100ms,
[&stop]() { //
std::cout << "Nobody loves me anymore :(\n";
stop = true;
}));
}
}, pipe_fds[0], chan, mut);
// Start an unlocker
start([](auto mut) -> void {
mut.unlock();
}, mut);
});
select_any
can return a value :
int result = select_any( //
event_read(in, &buffer, sizeof(buffer), [](ssize_t rc) { return 1; }), //
event_read(chan, buffer, [](bool) { return 2; }), //
event_timer(100ms, []() { return 3; })); //
switch(result) {
case 1:
std::cout << "Got data from the pipe \n";
break;
case 2:
std::cout << "Got data from the channel \n";
break;
default:
std::cout << "Nobody loves me anymore :(\n";
stop = true;
break;
}
See an example.
Head to the examples to see more code.
Please refer to the documentation.
Find the manual here.
The boson framework is distributed under the terms of The MIT License. Third parties are distributed under the terms of their own licenses. Third party code is the 3rdparty
directory.