Cppcoro
A library of C++ coroutine abstractions for the coroutines TS
Install / Use
/learn @lewissbaker/CppcoroREADME
CppCoro - A coroutine library for C++
The 'cppcoro' library provides a large set of general-purpose primitives for making use of the coroutines TS proposal described in N4680.
These include:
- Coroutine Types
- Awaitable Types
- Functions
- Cancellation
cancellation_tokencancellation_sourcecancellation_registration
- Schedulers and I/O
- Networking
- Metafunctions
- Concepts
This library is an experimental library that is exploring the space of high-performance, scalable asynchronous programming abstractions that can be built on top of the C++ coroutines proposal.
It has been open-sourced in the hope that others will find it useful and that the C++ community can provide feedback on it and ways to improve it.
It requires a compiler that supports the coroutines TS:
The Linux version is functional except for the io_context and file I/O related classes which have not yet been implemented for Linux (see issue #15 for more info).
Class Details
task<T>
A task represents an asynchronous computation that is executed lazily in that the execution of the coroutine does not start until the task is awaited.
Example:
#include <cppcoro/read_only_file.hpp>
#include <cppcoro/task.hpp>
cppcoro::task<int> count_lines(std::string path)
{
auto file = co_await cppcoro::read_only_file::open(path);
int lineCount = 0;
char buffer[1024];
size_t bytesRead;
std::uint64_t offset = 0;
do
{
bytesRead = co_await file.read(offset, buffer, sizeof(buffer));
lineCount += std::count(buffer, buffer + bytesRead, '\n');
offset += bytesRead;
} while (bytesRead > 0);
co_return lineCount;
}
cppcoro::task<> usage_example()
{
// Calling function creates a new task but doesn't start
// executing the coroutine yet.
cppcoro::task<int> countTask = count_lines("foo.txt");
// ...
// Coroutine is only started when we later co_await the task.
int lineCount = co_await countTask;
std::cout << "line count = " << lineCount << std::endl;
}
API Overview:
// <cppcoro/task.hpp>
namespace cppcoro
{
template<typename T>
class task
{
public:
using promise_type = <unspecified>;
using value_type = T;
task() noexcept;
task(task&& other) noexcept;
task& operator=(task&& other);
// task is a move-only type.
task(const task& other) = delete;
task& operator=(const task& other) = delete;
// Query if the task result is ready.
bool is_ready() const noexcept;
// Wait for the task to complete and return the result or rethrow the
// exception if the operation completed with an unhandled exception.
//
// If the task is not yet ready then the awaiting coroutine will be
// suspended until the task completes. If the the task is_ready() then
// this operation will return the result synchronously without suspending.
Awaiter<T&> operator co_await() const & noexcept;
Awaiter<T&&> operator co_await() const && noexcept;
// Returns an awaitable that can be co_await'ed to suspend the current
// coroutine until the task completes.
//
// The 'co_await t.when_ready()' expression differs from 'co_await t' in
// that when_ready() only performs synchronization, it does not return
// the result or rethrow the exception.
//
// This can be useful if you want to synchronize with the task without
// the possibility of it throwing an exception.
Awaitable<void> when_ready() const noexcept;
};
template<typename T>
void swap(task<T>& a, task<T>& b);
// Creates a task that yields the result of co_await'ing the specified awaitable.
//
// This can be used as a form of type-erasure of the concrete awaitable, allowing
// different awaitables that return the same await-result type to be stored in
// the same task<RESULT> type.
template<
typename AWAITABLE,
typename RESULT = typename awaitable_traits<AWAITABLE>::await_result_t>
task<RESULT> make_task(AWAITABLE awaitable);
}
You can create a task<T> object by calling a coroutine function that returns
a task<T>.
The coroutine must contain a usage of either co_await or co_return.
Note that a task<T> coroutine may not use the co_yield keyword.
When a coroutine that returns a task<T> is called, a coroutine frame
is allocated if necessary and the parameters are captured in the coroutine
frame. The coroutine is suspended at the start of the coroutine body and
execution is returned to the caller and a task<T> value that represents
the asynchronous computation is returned from the function call.
The coroutine body will start executing when the task<T> value is
co_awaited. This will suspend the awaiting coroutine and start execution
of the coroutine associated with the awaited task<T> value.
The awaiting coroutine will later be resumed on the thread that completes
execution of the awaited task<T>'s coroutine. ie. the thread that
executes the co_return or that throws an unhandled exception that terminates
execution of the coroutine.
If the task has already run to completion then awaiting it again will obtain the already-computed result without suspending the awaiting coroutine.
If the task object is destroyed before it is awaited then the coroutine
never executes and the destructor simply destructs the captured parameters
and frees any memory used by the coroutine frame.
shared_task<T>
The shared_task<T> class is a coroutine type that yields a single value
asynchronously.
It is 'lazy' in that execution of the task does not start until it is awaited by some coroutine.
It is 'shared' in that the task value can be copied, allowing multiple references to the result of the task to be created. It also allows multiple coroutines to concurrently await the result.
The task will start executing on the thread that first co_awaits the task.
Subsequent awaiters will either be suspended and be queued for resumption
when the task completes or will continue synchronously if the task has
already run to completion.
If an awaiter is suspended while waiting for the task to complete then
it will be resumed on the thread that completes execution of the task.
ie. the thread that executes the co_return or that throws the unhandled
exception that terminates execution of the coroutine.
API Summary
namespace cppcoro
{
template<typename T = void>
class shared_task
{
public:
using promise_type = <unspecified>;
using value_type = T;
shared_task() noexcept;
shared_task(const shared_task& other) noexcept;
shared_task(shared_task&& other) noexcept;
shared_task& operator=(const shared_task& other) noexcept;
shared_task& operator=(shared_task&& other) noexcept;
void swap(shared_task& other) noexcept;
// Query if the task has completed and the result is ready.
bool is_ready() const noexcept;
// Returns an operation that when awaited will suspend the
// current coroutine until the task completes and the result
// is available.
//
// The type of the result of the 'co_await someTask' expression
// is an l-value reference to the task's result value (unless T
// is void in which case the expression has type 'void').
// If the task completed with an unhandled exception then the
// exception will be rethrown by the co_await expression.
Awaiter<T&> operator co_await() const noexcept;
// Returns an operation that when awaited will suspend the
// calling coroutine until the task completes and the result
// is available.
//
// The result is not returned from the co_await expression.
// This can be used to synchronize with the task without the
// possibility
Related Skills
node-connect
333.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
333.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
82.0kCommit, push, and open a PR
