stlab / libraries

ASL libraries will be migrated here in the stlab namespace, new libraries will be created here.
https://stlab.cc
Boost Software License 1.0
660 stars 65 forks source link

Portable Executor port to Rust #532

Open nickpdemarco opened 9 months ago

nickpdemarco commented 9 months ago

This PR reimplements stlab::priority_task_system in Rust.

Usage

The rust port is chosen with a cmake argument, as in:

cmake -S . -B ../BUILD -GNinja -DCMAKE_CXX_STANDARD=17 -DCMAKE_BUILD_TYPE=Release -DSTLAB_TASK_SYSTEM=experimental_rust

The build will require an installation of cargo; otherwise, it should work out of the box.

To test this implementation, build with cmake as above, and then run ctest from the build directory.

Implementation

For greater readability and easier-to-prove safety, the C++ implementation has been broken into four components:

DropJoinThreadPool

Like scoped_threadpool, but the scope is tied to an object's lifetime, rather than a function call.

CoarsePriorityQueue

A priority queue with three priorities.

NotificationQueue

A threadsafe CoarsePriorityQueue.

Waiter

A faithful copy of stlab::detail::waiter. It may be prudent to rewrite this in terms of the Rust-native thread::park

PriorityTaskSystem

Building on the above components, this struct contains the algorithm essential to the original C++ implementation. Namely (quoting the inline documentation):

/// A portable work-stealing task scheduler with three priorities.
///
/// This scheduler spins up a number of threads corresponding to the amount of parallelism available
/// on the target platform, namely, std::thread::available_parallelism() - 1. Each thread is
/// assigned a threadsafe priority queue. To reduce contention on push and pop operations, a thread 
/// will first attempt to acquire the lock for its own queue without blocking.
/// If that fails, it will attempt the same non-blocking push/pop for each other priority queue in
/// the scheduler. Finally, if each of those attempts also fail, the thread will attempt a blocking
/// push/pop on its own priority queue.
///
/// The `add_thread` API is intended to mitigate the possibility of deadlock by spinning up a new
/// worker thread that non-blockingly polls all of the system's priority queues, and then sleeps
/// until `wake()` is called.
sean-parent commented 9 months ago

The usage instructions should be added to the readme file.