Make a controllable thread


#1

I think this is something like a pattern:
I have an helper thread that I want to control from the main program.
So I made a struct for setting something before the thread start.
When it starts it takes ownership of the struct and I would like to return an object containing an Arc of an internal struct that holds some Condvars, AtomicBools and the JoinHandle of the thread. The problem is I can’t insert the JoinHandle inside the same Arc because I need the Arc inside the same thread.
So I should use two Arc or return a couple with the Arc and the JoinHandle and give the JoinHandle to the Stop function. Every of these solutions I found not much elegant and ergonomic.
Is there a better solution I didn’t see?


#2

Let’s bring some context:

use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

fn main() {

    struct SharedData {
        time_to_exit: AtomicBool,
    }
    let shared_data = Arc::new(SharedData {
        time_to_exit: AtomicBool::new(false)
    });
    let shared_data2 = shared_data.clone();
    let join_handle = thread::spawn(move || {
        while !shared_data.time_to_exit.load(Ordering::SeqCst) {
            thread::sleep(Duration::from_millis(100));
        }
        println!("thread - done");
    });
    shared_data2.time_to_exit.store(true, Ordering::SeqCst);
    join_handle.join().unwrap();
    println!("main - done");
}

SharedData is shared data, join_handle is join handle, join handle
belong only to the thread that start another thread, it not belong another thread,
so what sense to hold it inside SharedData? put it near SharedData,
if you use this patter a lot, create someting:

struct ThreadInfo {
  shared_data: Arc<SharedInfo>,
  join_handle: JoinHandle<()>,
}

#3

The problem is that if I have to share the control of the thread with another thread I can’t clone the JoinHandle. So I can’t clone the ThreadInfo struct…
On the other hand if I return the couple (SharedData, JoinHandle) I can’t simply call a stop function on one struct, but I have to pass in also the JoinHandle.


#4

Ok, I think I found a nice solution:
I make a struct like your ThreadInfo and I impl a get_arc method that returns a clone of the internal arc, so I can call the methods of the internal SharedInfo.
In the end I have something like this:

[code]pub struct UpThread{
join_handle: JoinHandle<()>,
arc: Arc
}

pub struct UpThreadInternals {
stop: AtomicBool,
lock: Mutex,
cvar: Condvar
}

impl UpThread{
pub fn update(&self){
self.arc.update();
}
pub fn get_arc(&self) -> Arc{
self.arc.clone()
}
pub fn stop(self){
if let Ok(ut) = Arc::try_unwrap(self.arc){
ut.stop();
self.join_handle.join();
} else {
//log
}
}
}

impl UpThreadInternals{
pub fn update(&self){
let mut to_update = self.lock.lock().unwrap();
*to_update = true;
self.cvar.notify_one();
}
fn stop(self) {
self.stop.store(true, Ordering::Relaxed);
}
}
[/code]