https://github.com/p-ranav/psched
Priority-based Task Scheduling for Modern C++
https://github.com/p-ranav/psched
aging concurrency cpp17 header-only lightweight mit-license priority priority-modulation priority-scheduling queue queueing scheduling single-header single-header-lib task-management task-parallelism task-queue task-scheduler task-starvation threading
Last synced: 16 days ago
JSON representation
Priority-based Task Scheduling for Modern C++
- Host: GitHub
- URL: https://github.com/p-ranav/psched
- Owner: p-ranav
- License: mit
- Created: 2020-07-28T17:37:32.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2021-01-29T13:14:47.000Z (over 4 years ago)
- Last Synced: 2024-05-12T00:03:15.977Z (about 1 year ago)
- Topics: aging, concurrency, cpp17, header-only, lightweight, mit-license, priority, priority-modulation, priority-scheduling, queue, queueing, scheduling, single-header, single-header-lib, task-management, task-parallelism, task-queue, task-scheduler, task-starvation, threading
- Language: C++
- Homepage:
- Size: 873 KB
- Stars: 82
- Watchers: 5
- Forks: 10
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# psched
`psched` is a lightweight library that provides a priority-based task scheduler for modern C++.
* The `psched` scheduler manages an array of concurrent queues, each queue assigned a priority-level
* A task, when scheduled, is enqueued onto one of queues based on the task's priority
* A pool of threads executes ready tasks, starting with the highest priority
* The priority of starving tasks is modulated based on the age of the task
![]()
## Getting Started
Consider the task set below. There are three periodic tasks: `a`, `b` and `c`.
| Task | Period (ms) | Burst Time (ms) | Priority |
|------|-------------|-----------------|-------------|
| a | 250 | 130 | 0 (Lowest) |
| b | 500 | 390 | 1 |
| c | 1000 | 560 | 2 (Highest) |Here, _burst time_ refers to the amount of time required by the task for executing on CPU.
### Create a `PriorityScheduler`
First, let's create a scheduler:
```cpp
#include
#include
using namespace psched;int main() {
PriorityScheduler,
queues<3, maintain_size<100, discard::oldest_task>>,
aging_policy<
task_starvation_after,
increment_priority_by<1>
>>
scheduler;
```
### Create a `Task`
Create the first task, `Task a` like below. The task "performs work" for 130ms. The post-completion callback, called when the task has completed, can be used to study the temporal behavior of the task, e.g., waiting time, burst time, and turnaround time.
```cpp
Task a(
// Task action
[] { std::this_thread::sleep_for(std::chrono::milliseconds(130)); },
// Task post-completion callback
[](const TaskStats &stats) {
std::cout << "[Task a] ";
std::cout << "Waiting time = " << stats.waiting_time() << "ms; ";
std::cout << "Burst time = " << stats.burst_time() << "ms; ";
std::cout << "Turnaround time = " << stats.turnaround_time() << "ms\n";
}
);
```
### Schedule the task
Now, we can write a simple periodic timer that schedules this task at `priority<0>`:```cpp
auto timer_a = std::thread([&scheduler, &a]() {
while (true) {
// Schedule the task
scheduler.schedule>(a);
// Sleep for 250ms and repeat
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
});
```### Schedule more tasks
We can repeat the above code for tasks `b` and `c`:
```cpp
Task b(
// Task action
[] { std::this_thread::sleep_for(std::chrono::milliseconds(390)); },
// Task post-completion callback
[](const TaskStats &stats) {
std::cout << "[Task b] ";
std::cout << "Waiting time = " << stats.waiting_time() << "ms; ";
std::cout << "Burst time = " << stats.burst_time() << "ms; ";
std::cout << "Turnaround time = " << stats.turnaround_time() << "ms\n";
});auto timer_b = std::thread([&scheduler, &b]() {
while (true) {
scheduler.schedule>(b);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
});Task c(
// Task action
[] { std::this_thread::sleep_for(std::chrono::milliseconds(560)); },
// Task post-completion callback
[](const TaskStats &stats) {
std::cout << "[Task c] ";
std::cout << "Waiting time = " << stats.waiting_time() << "ms; ";
std::cout << "Burst time = " << stats.burst_time() << "ms; ";
std::cout << "Turnaround time = " << stats.turnaround_time() << "ms\n";
});auto timer_c = std::thread([&scheduler, &c]() {
while (true) {
scheduler.schedule>(c);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
});timer_a.join();
timer_b.join();
timer_c.join();
}
```Running this sample may yield the following output:
```bash
./multiple_periodic_tasks
[Task a] Waiting time = 0ms; Burst time = 133ms; Turnaround time = 133ms
[Task c] Waiting time = 0ms; Burst time = 563ms; Turnaround time = 563ms
[Task b] Waiting time = 0ms; Burst time = 395ms; Turnaround time = 395ms
[Task a] Waiting time = 60ms; Burst time = 134ms; Turnaround time = 194ms
[Task a] Waiting time = 0ms; Burst time = 131ms; Turnaround time = 131ms
[Task b] Waiting time = 0ms; Burst time = 390ms; Turnaround time = 390ms
[Task a] Waiting time = 3ms; Burst time = 135ms; Turnaround time = 139ms
[Task a] Waiting time = 0ms; Burst time = 132ms; Turnaround time = 132ms
[Task b] Waiting time = 8ms; Burst time = 393ms; Turnaround time = 402ms
[Task c] Waiting time = 0ms; Burst time = 561ms; Turnaround time = 561ms
[Task a] Waiting time = 6ms; Burst time = 133ms; Turnaround time = 139ms
[Task b] Waiting time = [Task a] Waiting time = 0ms; Burst time = 393ms; Turnaround time = 393ms
0ms; Burst time = 133ms; Turnaround time = 133ms
[Task a] Waiting time = 11ms; Burst time = 134ms; Turnaround time = 145ms
[Task a] Waiting time = 0ms; Burst time = 134ms; Turnaround time = 134ms
[Task b] Waiting time = 11ms; Burst time = 394ms; Turnaround time = 405ms
[Task c] Waiting time = 0ms; Burst time = 560ms; Turnaround time = 560ms
[Task a] Waiting time = 7ms; Burst time = 132ms; Turnaround time = 139ms
[Task b] Waiting time = 0ms; Burst time = 390ms; Turnaround time = 390ms
[Task a] Waiting time = 0ms; Burst time = 130ms; Turnaround time = 130ms
[Task a] Waiting time = 17ms; Burst time = 130ms; Turnaround time = 148ms
[Task a] Waiting time = 0ms; Burst time = 131ms; Turnaround time = 131ms
[Task b] Waiting time = 10ms; Burst time = 390ms; Turnaround time = 401ms
[Task c] Waiting time = 0ms; Burst time = 560ms; Turnaround time = 560ms
```## Building Samples
```bash
git clone https://github.com/p-ranav/psched
cd psched
mkdir build && cd build
cmake -DPSCHED_SAMPLES=ON ..
make
```## Generating Single Header
```bash
python3 utils/amalgamate/amalgamate.py -c single_include.json -s .
```## Contributing
Contributions are welcome, have a look at the CONTRIBUTING.md document for more information.## License
The project is available under the MIT license.