All Projects → duckie → Boson

duckie / Boson

Licence: mit
A C++14 framework for asynchronous I/O, cooperative multitasking and green threads scheduling

Programming Languages

cplusplus
227 projects

Projects that are alternatives of or similar to Boson

Mioco
[no longer maintained] Scalable, coroutine-based, fibers/green-threads for Rust. (aka MIO COroutines).
Stars: ✭ 125 (-18.83%)
Mutual labels:  coroutines, fibers, io
May
rust stackful coroutine library
Stars: ✭ 909 (+490.26%)
Mutual labels:  coroutines, fibers, io
aioudp
Asyncio UDP server
Stars: ✭ 21 (-86.36%)
Mutual labels:  async-programming, asynchronous-tasks
muco
Multithreaded Coroutines library
Stars: ✭ 20 (-87.01%)
Mutual labels:  coroutines, fibers
Co2
A C++ await/yield emulation library for stackless coroutine
Stars: ✭ 278 (+80.52%)
Mutual labels:  coroutines, async-programming
Unityfx.async
Asynchronous operations (promises) for Unity3d.
Stars: ✭ 143 (-7.14%)
Mutual labels:  coroutines, async-programming
Minicoro
Single header asymmetric stackful cross-platform coroutine library in pure C.
Stars: ✭ 164 (+6.49%)
Mutual labels:  coroutines, fibers
Creed
Sophisticated and functionally-minded async with advanced features: coroutines, promises, ES2015 iterables, fantasy-land
Stars: ✭ 265 (+72.08%)
Mutual labels:  coroutines, async-programming
asynchronous
A D port of Python's asyncio library
Stars: ✭ 35 (-77.27%)
Mutual labels:  coroutines, fibers
Lwt
OCaml promises and concurrent I/O
Stars: ✭ 505 (+227.92%)
Mutual labels:  fibers, io
Elle
The Elle coroutine-based asynchronous C++ development framework.
Stars: ✭ 459 (+198.05%)
Mutual labels:  coroutines, fibers
Fibertaskinglib
A library for enabling task-based multi-threading. It allows execution of task graphs with arbitrary dependencies.
Stars: ✭ 679 (+340.91%)
Mutual labels:  coroutines, fibers
Poseidon
Poseidon Server Framework (refactor WIP)
Stars: ✭ 162 (+5.19%)
Mutual labels:  coroutines, fibers
Zewo
Lightweight library for web server applications in Swift on macOS and Linux powered by coroutines.
Stars: ✭ 1,856 (+1105.19%)
Mutual labels:  coroutines, fibers
AIO
Coroutine-based multithreading library for Delphi
Stars: ✭ 99 (-35.71%)
Mutual labels:  coroutines, fibers
Umka Lang
Umka: a statically typed embeddable scripting language
Stars: ✭ 308 (+100%)
Mutual labels:  coroutines, fibers
Venice
Coroutines, structured concurrency and CSP for Swift on macOS and Linux.
Stars: ✭ 1,501 (+874.68%)
Mutual labels:  coroutines, fibers
Kotlinmultiplatform mvvm
Android & iOS App using MVVM pattern and LiveData on the presentation layer + Clean Arch on the common shared code.
Stars: ✭ 135 (-12.34%)
Mutual labels:  coroutines
Geojsonio
Convert many data formats to & from GeoJSON & TopoJSON
Stars: ✭ 132 (-14.29%)
Mutual labels:  io
Splitties
A collection of hand-crafted extensions for your Kotlin projects.
Stars: ✭ 1,945 (+1162.99%)
Mutual labels:  coroutines

The Boson framework

Travis CI Build Status codecov.io

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:

  • The Go routines
  • The net poller
  • The channels

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.

What's the point ?

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:

  • Routines (or fibers) are lightweight compared to threads, to launch and to schedule.
  • Interruption points are known by the developer, whereas they are not when scheduling threads.

Other frameworks exist, what is particular about Boson ?

  • Ease of use: The learning curve is very gentle, especially for C and Go developers used to system interfaces.
  • Select statement: The select_* statement is versatile and allows programming constructs that are hard to reproduce without it.
  • System calls interception: Libraries that have not been prepared to can be used in a asynchronized way with a LD_PRELOAD trick.

Quick overview

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.

Launch an instance

This snippet just launches a simple routine that exits immediately.

boson::run(1 /* number of thread */, []() {
  std::cout << "Hello world" << std::endl;
});

System calls

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.

Channels

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

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.

See other examples

Head to the examples to see more code.

How to build

Please refer to the documentation.

Documentation

Find the manual here.

License

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.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].