Crates.io | taskchain |
lib.rs | taskchain |
version | 0.1.4 |
source | src |
created_at | 2024-09-17 03:47:33.510117 |
updated_at | 2024-09-17 22:19:42.283377 |
description | A block-based, non-circular double-linked list implementation for Rust. |
homepage | |
repository | https://github.com/pecktalk/pex/tree/main/taskchain |
max_upload_size | |
id | 1377106 |
size | 35,378 |
TaskChain
is a Rust crate that ensures tasks are executed sequentially based on signals, preventing parallel execution. It manages tasks using a signaling mechanism, allowing tasks to either proceed based on an "ANY" task signal or a specified task signal. This crate is useful in scenarios where precise control over task execution order is needed.
Signal
and Kinds
enums to control the task flow.TaskChain
instance is dropped, the next signal is automatically triggered, ensuring no deadlocks.The following example demonstrates how to use TaskChain
for managing sequential tasks:
use std::sync::{Arc, atomic::{AtomicU32, Ordering}};
use std::thread;
use std::time::Duration;
use taskchain::{Kinds, Signal, CondvarPair, TaskChain};
// Create a shared CondvarPair and an atomic counter.
let cvp = Arc::new(CondvarPair::new(Signal::INACTIVE));
let count = AtomicU32::new(0);
// Start the thread scope to manage multiple threads.
thread::scope(|s| {
// First thread that doesn't wait for any signal but sends `TRIGGER(Kinds::SPECIFIED(0))`.
thread::Builder::new()
.name("first".to_string())
.spawn_scoped(s, || {
let mut pl = TaskChain::new(
Arc::clone(&cvp),
Kinds::ANY,
Signal::TRIGGER(Kinds::SPECIFIED(0)),
);
assert_eq!(count.load(Ordering::SeqCst), 0);
count.fetch_add(1, Ordering::SeqCst); // Increment the counter.
thread::sleep(Duration::from_millis(100));
pl.notify(); // Notify the second thread.
})
.unwrap();
// Second thread that waits for the `TRIGGER(Kinds::SPECIFIED(0))` signal.
thread::Builder::new()
.name("second".to_string())
.spawn_scoped(s, || {
let mut pl = TaskChain::new(
Arc::clone(&cvp),
Kinds::SPECIFIED(0),
Signal::TRIGGER(Kinds::SPECIFIED(1)),
);
pl.wait(Duration::ZERO); // Wait for the first thread's signal.
assert_eq!(count.load(Ordering::SeqCst), 1); // Ensure first thread incremented.
count.fetch_add(1, Ordering::SeqCst); // Increment the counter.
})
.unwrap();
// Third thread that waits for the `TRIGGER(Kinds::SPECIFIED(1))` signal.
thread::Builder::new()
.name("third".to_string())
.spawn_scoped(s, || {
let mut pl = TaskChain::new(
Arc::clone(&cvp),
Kinds::SPECIFIED(1),
Signal::INACTIVE
);
pl.wait(Duration::ZERO); // Wait for the second thread's signal.
assert_eq!(count.load(Ordering::SeqCst), 2); // Ensure second thread incremented.
count.fetch_add(1, Ordering::SeqCst); // Increment the counter.
})
.unwrap();
});
// Ensure all threads completed and incremented the counter.
assert_eq!(count.load(Ordering::SeqCst), 3);
• CondvarPair: A structure managing the synchronization of tasks via signals. • Kinds Enum: Specifies the kind of task expected to proceed (ANY or SPECIFIED). • Signal Enum: Controls the signaling in the taskchain (INACTIVE or TRIGGER with a Kinds value). • TaskChain: The main structure managing task execution flow.
Tasks can wait for a specified duration before timing out. If a timeout occurs, the task will stop waiting and proceed without receiving the expected signal:
let mut pl = TaskChain::new(
Arc::clone(&cvp),
Kinds::SPECIFIED(0),
Signal::INACTIVE
);
if pl.wait(Duration::from_secs(2)) {
println!("Task proceeded with the expected signal.");
} else {
println!("Task timed out waiting for the signal.");
}
Licensed under the Apache License, Version 2.0 (the “License”). You may not use this file except in compliance with the License. You may obtain a copy of the License at Apache License 2.0.