A C++20 coroutine runtime for structured concurrency β tasks, a thread-pool scheduler, when_all, channels, async mutex/event and generators. Header-first, zero dependencies.
C++20 gave the language coroutines but almost no library to use them. potok
fills that gap with a small, composable runtime in the spirit of cppcoro:
lazy task<T>s, an executor to run them on, and the combinators to structure
concurrent work β all with clean RAII and exception propagation, and no
dependencies beyond the standard library.
#include <potok/potok.hpp>
using namespace potok;
using namespace std::chrono_literals;
task<int> square(static_thread_pool& pool, int x) {
co_await pool.schedule(); // hop onto a worker thread
co_return x * x;
}
task<int> sum_of_squares(static_thread_pool& pool) {
std::vector<task<int>> work;
for (int i = 1; i <= 10; ++i) work.push_back(square(pool, i));
auto results = co_await when_all(std::move(work)); // run them in parallel
int total = 0;
for (int r : results) total += r;
co_return total; // 385
}
int main() {
static_thread_pool pool;
int total = sync_wait(sum_of_squares(pool)); // bridge sync -> async
}| Type | What it gives you |
|---|---|
task<T> |
A lazy coroutine. Starts when awaited (symmetric transfer, no wasted frames), propagates results and exceptions to the awaiter. |
sync_wait(awaitable) |
Runs an awaitable to completion and blocks until it returns β the door from main() into async code. |
static_thread_pool |
A pool of worker threads plus a timer. co_await pool.schedule() resumes on a worker; co_await pool.schedule_after(d) resumes after a delay. |
when_all(...) |
Await many tasks concurrently; returns a vector or tuple of results, rethrowing the first exception. |
channel<T> |
A bounded MPMC queue coroutines pass values through (co_await ch.send/recv), with back-pressure and close semantics. |
async_mutex |
A mutex you co_await instead of blocking a thread; yields an RAII guard. |
async_manual_reset_event |
A one-to-many signal coroutines can await. |
generator<T> |
A lazy pull sequence built with co_yield, usable in a range-for. |
detached_task |
Fire-and-forget background coroutine. |
- Structured.
when_allties concurrent lifetimes together; results and errors come back to one place instead of leaking through callbacks. - No callback soup. Async code is written top-to-bottom with
co_await. - Composable. Everything is an awaitable, so the pieces combine:
co_await pool.schedule_after(50ms),co_await ch.recv(),co_await mutex.lock(). - Exception-safe. Exceptions propagate across
co_awaitand out ofwhen_all/sync_waitjust like ordinary calls.
task<void> produce(static_thread_pool& pool, channel<std::string>& ch) {
co_await pool.schedule();
for (int i = 0; i < 5; ++i) co_await ch.send("msg#" + std::to_string(i));
ch.close();
}
task<void> consume(static_thread_pool& pool, channel<std::string>& ch) {
co_await pool.schedule();
while (auto msg = co_await ch.recv()) // nullopt once closed & drained
handle(*msg);
}
task<void> run(static_thread_pool& pool) {
channel<std::string> ch(2); // small buffer => real back-pressure
std::vector<task<void>> both;
both.push_back(produce(pool, ch));
both.push_back(consume(pool, ch));
co_await when_all(std::move(both));
}Needs a C++20 compiler with coroutines (GCC β₯ 10, Clang β₯ 14, MSVC β₯ 19.28) and CMake β₯ 3.14. No third-party dependencies.
git clone https://github.com/VirusAid/potok.git
cd potok
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failureadd_subdirectory(potok)
target_link_libraries(my_app PRIVATE potok::potok)The runtime is header-first; only the thread pool is compiled (one small .cpp).
- Scheduling is a simple shared FIFO run-queue β fair and correct, not a work-stealing deque. Great up to moderate core counts.
channeland the async primitives guard their state with astd::mutexand resume waiters inline; ideal for coordination, not for microsecond-latency hot loops.- No OS I/O reactor (epoll/IOCP) yet:
potokschedules CPU work and timers. Networking on top of the same awaitable model is a natural next layer.
It is a real, tested runtime β the concurrency tests (an 8-worker Γ 500-iter mutex stress, a 1000-item channel pipeline) pass repeatably β but young. See SECURITY.md to report issues.
MIT β see LICENSE. Free for any use, including commercial.