# TaskChain [![Crates.io](https://img.shields.io/crates/v/taskchain.svg)](https://crates.io/crates/taskchain) [![Docs.rs](https://docs.rs/taskchain/badge.svg)](https://docs.rs/taskchain) `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. ## Features - **Sequential Task Execution**: Tasks proceed one at a time based on signals. - **Two Modes of Task Execution**: - **ANY Mode**: Multiple tasks can wait, but only one task will be triggered to proceed. - **Specified Mode**: Only a specific task is allowed to proceed when triggered. - **Signal-Based Control**: Using `Signal` and `Kinds` enums to control the task flow. - **Timeout Support**: Tasks can optionally wait for a specified duration before proceeding. - **Automatic Signaling**: If a `TaskChain` instance is dropped, the next signal is automatically triggered, ensuring no deadlocks. ## Usage ### Example: Sequential Task Execution The following example demonstrates how to use `TaskChain` for managing sequential tasks: ```rust 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); ``` ## Features Overview • 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. ## Timeout Support 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: ```rust 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."); } ``` ## License 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.