SkillAgentSearch skills...

Asrt

An open source task scheduling library ASRT (Async Runtime) written in modern C++ tailored for embedded linux systems.

Install / Use

/learn @ozhang3/Asrt
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

ASRT

An open source task scheduling library ASRT (Async Runtime) written in modern C++ tailored for embedded linux systems.

ASRT is a header-only C++ concurrency/networking library that makes writing performant and safe embedded applications a breeze. Implementations of a task scheduler and C++ abstractions for posix objects like sockets and pipes are provided out of the box. If you are comfortable with C++11 or above and have written networking applications, you are good to go! No more awkward wrappers over raw system calls and manual event loops in your otherwise structured (I hope) C++ program.

Embracing the Sender/Receiver Model

The fully sender/receiver-compatible v2 branch of ASRT is currently under active development! Please see Senders/Receivers section for a closer look on the story behind it all, the features we plan on supporting and all the cool things you will be able to do with it!

New in V1.2.0!

Now you can compose tasks before scheduling them for execution! See below for a sneak peek of this new feature.

#include <iostream>
#include "asrt/asrt.hpp"
#include "asrt/execution/execution.hpp"

using namespace asrt::execution;

int main() {

	// Compose tasks using the then() method
	auto composed_task = Task{[] {
		std::cout << "Task 1 executed." << std::endl;
		return 42;
	}}
	| then([](int value) {
		std::cout << "Task 2 executed with value: " << value << std::endl;
		return value * 2;
	})
	| then([](int value) {
		std::cout << "Task 3 executed with value: " << value << std::endl;
	});

	// Post the composed task to the global default scheduler
	asrt::Post(std::move(composedTask));

	// The composed task will be executed here
	asrt::Run();

	return 0;
}

Please refer to the Task Composition section for a detailed introduction to the various ways to express dependency relationships between tasks and the underlying implementation that makes this possible,

Table of Contents

Why Another Task Scheduling Library?

Although task libraries abound in C++, with Boost::Asio, Intel's TBB and of course, NVDIA's stdexec that is on course for standard shipment with C++26, there seems to be a void in development of a task scheduler that's written specifically with embedded applications in mind. ASRT fills that void.

The design objectives of ASRT are as follows:

  • Safety. Safety always comes first in embedded applications. The ability of a piece of software to correctly function for extended periods of time without crashing or stalling is especially criticial In fields such as medical equipments and autonomous vehicles. ASRT is designed with a robust error handling and tracing mechanism. Users are shielded from directly interacting with the operation system. We use RAII abstractions over raw system resources whenever possible. All systems calls are traceable and systems erros are never ignored (either internally handled or passed on to the user). The library does not start or manage any threads whatsoever and that responsibility is left solely to the user. Synchronous signal handling is supported (with kernel verison > Linux 2.6.22) so that signals are handled gracefully and do not disrupt the normal program flow.

  • Performance. We understand the importance of performance to any C++ programmer ; ) As modern embedded applications become increasingly complex and increasingly inter-connected, the need for an efficient and low-latency task schedulign and networking framework is criticial is ever more important. Throughout the entire framework, expensive operations such as virtual function callss and dynamic allocations are avoided whenever posssible. Compile-time computations are preferred over run-time ones. Static polymorphism are utilised in place of run-time polymorphism. Use zero-cost/low-cost abstractions whenever possible. Benchmarks are regularly executed on differnt platforms and with differnt compilers.

  • Resources. Memory resources are often limited in embedded applications. ASRT understands this and avoids dynamic allocation at all costs. When that is not possible, ASRT gives users the abillity to integrate their custom memory allocation schemes into the framework through injecting astd::pmr::allocator (available with C++17) when constructing entites such as asrt::Executor and asrt::BasicSocket. These objects are said to be allocator-aware as they understand and can work with user-defined memory resources rather than always calling new and delete. Using allocators is of cource not mandatory. All ASRT objects can work without alloators, in which case they just default to using the global new and delete when dynamically allocating.

  • Extensibility Objects like asrt::Executor and asrt::BasicSocket are designed to be easily customized and extended. These base types are designed as CRTP interfaces to be extended by derived classes. For example. if you want to implement a custom UDP-Lite socket, you can implement asrt::BasicSocket's CRTP interface without having to write everything from scratch since the logic for opening. binding, and closing the sockets are entirely reusable. In fact, sockets like asrt::BasicStreamSocket and asrt::BasicDatagramSocket are exactly implemented by implementing the same asrt::BasicSocket interface. You can also see an example in the library of an implementation of a packet socket called asrt::BasicPacketSocketthat gives you an idea of you might want to implement your own socket.

Architecture Overview

The core components of the ASRT library can be logically grouped into three layers.

ASRT Core Componets

Os Abtstraction

At the very bottom, there is the Os Abtstraction layer that implements abstractions towards APIs/objects provided by or used to interact with the operation system. ASRT implements abstractions over communication objects such as asrt::BasicSocket and asrt::BasicNamedPipe on top of their posix equivalents. Another core component in this layer is the asrt::Reactor abstraction, which implemenmts the reactor design pattern. A reactor is a device that encapasulates a dedicated event loop that repeatedly calls poll(), epoll_wait()or io_uring_enter()and dispatches the reaped i/o events from those calls. Without native support on Linux for asynchronous i/o such as that provided by Window's overlapped i/o, a reactor is needed to emulate asynchrony. All ASRT i/o objects such as asrt::BasicStreamSocket and asrt::BasicNamedPipe support asynchronous i/o through underlying reactor.

Asynchrony/Concurrency

In this layer, asynchronous task scheduling is implememted through abstractions such as asrt::Executor. From a high-level view, an executor is simply a combination of task storage and execution policy. Tasks are function callables that are submitted by user for execution to the executor. Execution policy controls the how (can tasks be executed in parrallel), when (execute now or some time later) and where (which thread to execute the task on) the execution takes place. ASRT also implements timer abstractions such as asrt::BasicWaitableTimer and asrt::BasicPeriodicTimer which enable delayed or periodic task scheduling. They can also be used as standalone objects that enable custom timer expiry handling. Strands are another useful abstraction provided by the library that simplifies task synchronization in multithreaded use cases. By enqueuing mutually exclusive tasks in a asrt::Strand, you avoid needing to manually syncrhonize the tasks to prevent concurrent execution.

Application Prototypes

At the highest level, ASRT provides out-of-the-box implementation of reusable application components such as the asrt::TcpConnectionand asrt::UnixStreamConnection, which are simply different template instantiations of the same asrt::Connection base type. Interfaces such asrt::ClientInterface and asrt::ServerInterfacecan also be inherited/encapsulated by user implementations to enable typical client-server use cases.

Task Scheduling

Scheduling tasks is as easy as calling the global api asrt::Post() , which signals the underlying global default asrt::Executor to schedule your callable for immediate asynchronous execution (synchronous execution is also

View on GitHub
GitHub Stars104
CategoryDevelopment
Updated2mo ago
Forks25

Languages

C++

Security Score

95/100

Audited on Jan 20, 2026

No findings