Threading/Executable module #1

Merged
muellerr merged 12 commits from threading into main 2022-06-09 12:50:06 +02:00
2 changed files with 80 additions and 35 deletions
Showing only changes of commit e4b5df8287 - Show all commits

View File

@ -1,5 +1,3 @@
use std::time::Duration;
pub enum OpResult {
Ok,
}
@ -13,15 +11,13 @@ pub enum ExecutionType {
pub trait Executable {
type Error;
const EXEC_TYPE: ExecutionType;
const TASK_FREQ: Option<Duration>;
const TASK_NAME: &'static str;
fn periodic_op(&mut self, op_code: u32) -> Result<OpResult, Self::Error>;
fn periodic_op(&mut self, op_code: i32) -> Result<OpResult, Self::Error>;
}
trait ExecutableWithAssociatedFuncs {
type Error;
fn exec_type(&self) -> ExecutionType;
fn task_freq(&self) -> Option<Duration>;
fn task_name(&self) -> &'static str;
fn periodic_op(&mut self) -> Result<OpResult, Self::Error>;
}

View File

@ -5,7 +5,9 @@ use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;
struct ExampleTask {}
struct OneShotTask {}
struct FixedCyclesTask {}
struct PeriodicTask {}
#[derive(Debug)]
struct ExampleError {
@ -32,28 +34,63 @@ impl Error for ExampleError {
}
}
impl Executable for ExampleTask {
impl Executable for OneShotTask {
type Error = ExampleError;
const EXEC_TYPE: ExecutionType = ExecutionType::OneShot;
const TASK_FREQ: Option<Duration> = Some(Duration::from_millis(500));
const TASK_NAME: &'static str = "Test Task";
const TASK_NAME: &'static str = "One Shot Test Task";
fn periodic_op(&mut self, op_code: u32) -> Result<OpResult, ExampleError> {
if op_code == 0 {
println!("Periodic Operation OK!");
fn periodic_op(&mut self, op_code: i32) -> Result<OpResult, ExampleError> {
if op_code >= 0 {
println!("One-shot operation with operation code {op_code} OK!");
Ok(OpResult::Ok)
} else {
println!("Periodic Operation Fail!");
println!("One-shot operation failure by passing op code {op_code}!");
Err(ExampleError::new("Example Task Failure"))
}
}
}
impl Executable for FixedCyclesTask {
type Error = ExampleError;
const EXEC_TYPE: ExecutionType = ExecutionType::Cycles(5);
const TASK_NAME: &'static str = "Fixed Cycles Task";
fn periodic_op(&mut self, op_code: i32) -> Result<OpResult, ExampleError> {
if op_code >= 0 {
println!("Fixed-cycle operation with operation code {op_code} OK!");
Ok(OpResult::Ok)
} else {
println!("Fixed-cycle operation failure by passing op code {op_code}!");
Err(ExampleError::new("Example Task Failure"))
}
}
}
impl Executable for PeriodicTask {
type Error = ExampleError;
const EXEC_TYPE: ExecutionType = ExecutionType::Cycles(5);
const TASK_NAME: &'static str = "Fixed Cycles Task";
fn periodic_op(&mut self, op_code: i32) -> Result<OpResult, ExampleError> {
if op_code >= 0 {
println!("Periodic operation with operation code {op_code} OK!");
Ok(OpResult::Ok)
} else {
println!("Periodic operation failure by passing op code {op_code}!");
Err(ExampleError::new("Example Task Failure"))
}
}
}
fn main() {
let exec_task = ExampleTask {};
let jhandle = test_thread(exec_task, 0);
let exec_task2 = ExampleTask {};
let jhandle2 = test_thread(exec_task2, 1);
let exec_task = OneShotTask {};
let mut task_vec = Vec::new();
task_vec.push(exec_task);
let jhandle = test_thread(task_vec, Some(Duration::from_millis(500)), 0);
let exec_task2 = FixedCyclesTask {};
let mut task_vec2 = Vec::new();
task_vec2.push(exec_task2);
let jhandle2 = test_thread(task_vec2, Some(Duration::from_millis(1000)), 1);
jhandle
.join()
.expect("Joining thread failed")
@ -65,26 +102,38 @@ fn main() {
}
fn test_thread<T: Executable<Error = E> + Send + 'static, E: Error + Send + 'static>(
mut executable: T,
op_code: u32,
mut executable_vec: Vec<T>,
task_freq: Option<Duration>,
op_code: i32,
) -> JoinHandle<Result<OpResult, E>> {
thread::spawn(move || match T::EXEC_TYPE {
ExecutionType::OneShot => executable.periodic_op(op_code),
ExecutionType::Infinite => loop {
executable.periodic_op(op_code)?;
let freq = T::TASK_FREQ
.unwrap_or_else(|| panic!("No task frequency specified for task {}", T::TASK_NAME));
thread::sleep(freq)
},
ExecutionType::Cycles(cycles) => {
for _i in 0..cycles - 1 {
executable.periodic_op(op_code)?;
let freq = T::TASK_FREQ.unwrap_or_else(|| {
panic!("No task frequency specified for task {}", T::TASK_NAME)
});
thread::sleep(freq)
let mut cycle_counts = vec![0; executable_vec.len()];
let mut removal_flags = vec![false; executable_vec.len()];
thread::spawn(move || loop {
for (idx, executable) in executable_vec.iter_mut().enumerate() {
match T::EXEC_TYPE {
ExecutionType::OneShot => {
executable.periodic_op(op_code)?;
removal_flags[idx] = true;
}
ExecutionType::Infinite => {
executable.periodic_op(op_code)?;
}
ExecutionType::Cycles(cycles) => {
executable.periodic_op(op_code)?;
cycle_counts[idx] += 1;
if cycle_counts[idx] == cycles {
removal_flags[idx] = true;
}
}
}
Ok(OpResult::Ok)
}
executable_vec.retain(|_| !*removal_flags.iter().next().unwrap());
removal_flags.retain(|&i| i == false);
if executable_vec.is_empty() {
return Ok(OpResult::Ok);
}
let freq = task_freq
.unwrap_or_else(|| panic!("No task frequency specified for task {}", T::TASK_NAME));
thread::sleep(freq);
})
}