2

It seems like coroutines are normally found in higher level languages.

There seem to be several different definitions of them as well. I am trying to find a way to have the specifically called coroutines in C like we have in Lua.

 function foo()     
     print("foo", 1) 
     coroutine.yield() 
     print("foo", 2) 
 end 
phuclv
  • 37,963
  • 15
  • 156
  • 475
Patrick
  • 21
  • 2

5 Answers5

2

There is a new (as of version 1.53.0) coroutine library in the Boost C++ library: http://www.boost.org/doc/libs/1_53_0/libs/coroutine/doc/html/index.html

I'm unaware of a C library--I came across this question looking for one.

Samuel Powell
  • 1,116
  • 1
  • 10
  • 8
2

Nowadays, C++ provides coroutines natively as part of C++20.

Concerning the C language, they are not supported natively but several libraries provides them. Some are not portable as they rely on some architecture-dependent assembly instructions but some are portable as they use standard library functions like setjmp()/longjmp() or getcontext()/setcontext()/makecontext()/swapcontext(). There are also some original propositions like this one which uses the C language trick from the Duff's device.

N.B.: On my side, I designed this library.

Rachid K.
  • 4,490
  • 3
  • 11
  • 30
2

There's no language level support for coroutines in either C or C++.

You could implement them using assembler or fibres, but the result would not be portable and in the case of C++ you'd almost certainly lose the ability to use exceptions and be unable to rely on stack unwinding for cleanup.

In my opinion you should either use a language the supports them or not use them - implementing your own version in a language that doesn't support them is asking for trouble.

JoeG
  • 12,994
  • 1
  • 38
  • 63
  • Thanks Joe I was reading about doing this in assembly but I could not find any examples. Rolling my own solution in ASM would be suicide – Patrick Sep 14 '11 at 12:16
  • [coroutines were available since C++20?](https://stackoverflow.com/q/43503656/995714) – phuclv Jun 15 '22 at 16:19
1

Sorry - neither C nor C++ has support for coroutines. However, a simple search for "C coroutine: yields the following fascinating treatise on the problem: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html, although you may find his solution a bit - um - impractical

Mike Sokolov
  • 6,914
  • 2
  • 23
  • 31
  • Thanks. I have searched for many hours but that's the thing... I am looking for something production ready. – Patrick Sep 14 '11 at 12:04
  • C++17 will likely have a coroutine implementation. Current Proposal here: https://isocpp.org/files/papers/N3722.pdf – Atif Feb 19 '16 at 15:15
0

There's a bunch of coroutine libraries for C++. Here's one from RethinkDB.

There's also mine header-only library, which is tailored to be used with callbacks. I've tried Boost coroutines but I don't use them yet because of the incompatibility with valgrind. My implementation uses ucontext.h and works fine under valgrind so far.

With "standard" coroutines you have to jump thru some hoops to use them with callbacks. For example, here is how a working thread-safe (but leaking) Cherokee handler looks with Boost coroutines:

typedef coroutine<void()> coro_t;
auto lock = make_shared<std::mutex>();
coro_t* coro = new coro_t ([handler,buffer,&coro,lock](coro_t::caller_type& ca)->void {
  p1: ca();  // Pass the control back in order for the `coro` to initialize.
  coro_t* coro_ = coro;  // Obtain a copy of the self-reference in order to call self from callbacks.
  cherokee_buffer_add (buffer, "hi", 2); handler->sent += 2;
  lock->lock();  // Prevents the thread from calling the coroutine while it still runs.
  std::thread later ([coro_,lock]() {
    //std::this_thread::sleep_for (std::chrono::milliseconds (400));
    lock->lock();  // Wait for the coroutine to cede before resuming it.
    (*coro_)();  // Continue from p2.
  }); later.detach();
  p2: ca();  // Relinquish control to `cherokee_handler_frople_step` (returning ret_eagain).
  cherokee_buffer_add (buffer, ".", 1); handler->sent += 1;
});
(*coro)(); // Back to p1.
lock->unlock(); // Now the callback can run.

and here is how it looks with mine:

struct Coro: public glim::CBCoro<128*1024> {
  cherokee_handler_frople_t* _handler; cherokee_buffer_t* _buffer;
  Coro (cherokee_handler_frople_t *handler, cherokee_buffer_t* buffer): _handler (handler), _buffer (buffer) {}
  virtual ~Coro() {}
  virtual void run() override {
    cherokee_buffer_add (_buffer, "hi", 2); _handler->sent += 2;
    yieldForCallback ([&]() {
      std::thread later ([this]() {
        //std::this_thread::sleep_for (std::chrono::milliseconds (400));
        invokeFromCallback();
      }); later.detach();
    });
    cherokee_buffer_add_str (_buffer, "."); _handler->sent += 1;
  }
};
ArtemGr
  • 11,684
  • 3
  • 52
  • 85