Async.h – asynchronous, stackless subroutines in C
The async/await idiom is becoming increasingly popular. The first widely used language to include it was C#, and it has now spread into JavaScript and Rust. Now C/C++ programmers don't have to feel left out, because async.h is a header-only library that brings async/await to C!
Features:
- It's 100% portable C.
- It requires very little state (2 bytes).
- It's not dependent on an OS.
- It's a bit simpler to understand than protothreads because the async state is caller-saved rather than callee-saved.
#include "async.h" struct async pt; struct timer timer; async example(struct async *pt) { async_begin(pt); while(1) { if(initiate_io()) { timer_start(&timer); await(io_completed() || timer_expired(&timer)); read_data(); } } async_end; }
This library is basically a modified version of the idioms found in the Protothreads library by Adam Dunkels, so it's not truly ground breaking. I've made a few tweaks that make it more understandable and generate more compact code, and I also think it more cleanly maps to the async/await semantics than it does to true threading.
Protothreads and async.h are both based around local continuations, but where protothreads are callee-saved, async.h is caller-saved. This eliminates the need to pass in the local continuation to any async operations except async_begin
. This simplifies the macros that implement the async/await idiom, and even simplifies code that uses async.h.
Here's a simple example of fork-join style "parallelism":
#include "async.h" typedef struct { async_state; struct async nested1; struct async nested2; } example_state; example_state pt; async nested(struct async *pt){ async_begin(pt); ... async_end; } async example(example_state *pt) { async_begin(pt); // fork two nested async subroutines and wait until both complete async_init(&pt->nested1); async_init(&pt->nested2); await(async_call(nested, &pt->nested1) & async_call(nested, &pt->nested2)); // fork two nested async subroutines and wait until at least one completes async_init(&pt->nested1); async_init(&pt->nested2); await(async_call(nested, &pt->nested1) | async_call(nested, &pt->nested2)); async_end; }
from Hacker News https://ift.tt/2AzPTL6