Stable based threading 13/7/2023

This is an elegant, very small, Rust library for simple multi-threading. The use case below is 2 .. 1,000,000 of the Collatz Conjecture, but obviously it's suitable for many simple tasks. I called it Stables and Horses because the idea is that Horses are functions that are then sent from the stables as threads. The code is provided as-is with no support. I am not a programmer. I like computing but I also hate it. I have used this successfully with GiBs sized files, but use buffered IO, at least on file-system writes, because unbuffered IO can be obnoxiously slow and unpredictable.

Lib.rs

/// Very simple, quite efficient threading model for general tasks
///

use std::sync::{Arc, Mutex};
use std::thread;

// Type alias for an Option on a function

type Horse = Option<Box<dyn Fn() + 'static + Send>>;

pub struct Stables {
    count: usize,
    horses: Arc<Mutex<Vec<Horse>>>,
}

impl Stables {
    pub fn new(size: usize) -> Stables {
        let mut temp_horses: Vec<Horse> = Vec::with_capacity(size);
        for _ in 0..size {
            temp_horses.push(None);
        }
        Stables {
            count: size,
            horses: Arc::new(Mutex::new(temp_horses)),
        }
    }
    pub fn new_race(&self, func: Box<dyn Fn() + 'static + Send>) {
        let my_horses = Arc::clone(&self.horses);
        let mut my_horses = my_horses.lock().unwrap();
        for x in my_horses.iter_mut() {
            match x {
                Some(_) => continue,
                None => {
                    *x = Some(func);
                    return ();
                },
            }
        }
    }
   pub fn off(&self) {
        let my_horses = Arc::clone(&self.horses);
        let mut my_horses = my_horses.lock().unwrap();
        let mut threads = Vec::with_capacity(self.count);
        for x in my_horses.iter_mut() {
            match x {
                Some(_) => {
                    let q = x.take();
                    match q {
                        Some(f) => {
                            let clipclop = thread::spawn(move || {
                            f()
                            });
                            threads.push(clipclop);
                        }
                        None => {
                            continue;
                        }
                    }
                }
                None => {
                    continue;
                }
            }
        }
        for x in threads {
            x.join().unwrap();
        }
    }
}

Usage (example Main.rs)

use stables::Stables;
use std::sync::{Mutex,Arc};

fn main() {
    let test_out = Arc::new(Mutex::new(String::new()));
    let highest = Arc::new(Mutex::new(0));

    let ref_one = Arc::clone(&test_out);
    let ref_two = Arc::clone(&test_out);


    let count1 = Arc::clone(&highest);
    let count2 = Arc::clone(&highest);

    let my_stables = Stables::new(4);
    
    let job_one =  move || {
        for x in 2..5_000_00 {
            let c = collatz(x);
            let h = *count1.lock().unwrap();
            if c>h {
                println!("{:?}: {:?}", x, c);
                *count1.lock().unwrap()=c;
            }
        }

        *ref_one.lock().unwrap()=String::from("Hello");

    };
    let job_two = move || {
        for x in 5_000_00..=1_000_000 {
            let c = collatz(x);
            let h = *count2.lock().unwrap();
            if c>h {
                println!("{:?}: {:?}", x, c);
                *count2.lock().unwrap()=c;
            }
        }
        *ref_two.lock().unwrap()=String::from("Goodbye");
    };

    my_stables.new_race(Box::new(job_one));
    my_stables.new_race(Box::new(job_two));
    my_stables.off();    
    my_stables.off();
    println!("{:?}", test_out);
}

fn collatz(number: u64) -> usize{
    let mut number =  number;
    let mut list: Vec<u64> = Vec::new();

    while number!=1 {
        list.push(number);
        if number%2 == 0 {
            number=number/2;
        } else {
            number = (3*number) + 1;
        }
    }

    list.push(number);
    return list.len()-1;

}
back

© John B Everitt