首页 文章

如何在线程之间共享对AtomicBool的访问权限?

提问于
浏览
4

我有这个小程序 - 基本上我希望一个线程能够告诉对方通过结构中的共享布尔值来停止 .

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

struct Test {
    should_stop: AtomicBool,
    running_thread_handles: Vec<JoinHandle<()>>
}

impl Test {
    fn new() -> Test {
        Test { 
            should_stop: AtomicBool::new(false), 
            running_thread_handles: Vec::new() 
        }
    }

    fn stop(&mut self) {
        self.should_stop.store(true, Ordering::Relaxed);
    }

    fn start(&mut self) {
        let handle = thread::spawn(move || {
            loop {
                println!("Looping");
                thread::sleep(Duration::from_millis(500));

                // I want to effectively do this...
                /*
                if self.stop_bool.load(Ordering::Relaxed) {
                    println!("Stopping");
                    break;
                }*/
            }
        });

        self.running_thread_handles.push(handle);
    }
}

impl Drop for Test {
    fn drop(&mut self) {
        self.stop();

        // Here I want to iterate the self.running_thread_handles and
        // make sure they are cleaned up
    }
}

// I expect to see a 4 "Looping" messages and then a "Stopping" message
fn main() {
   let mut test = Test::new();
   test.start();
   thread::sleep(Duration::from_millis(2000));
   test.stop();
}

也许有一个更好的方法,但我认为这可能是了解一生的东西的好方法 .

我以为我只需要 Arc 所以我试过这个:

fn start(&mut self) {
    let stop_bool = Arc::new(&self.should_stop).clone();

    let handle = thread::spawn(move || {
        loop {
            println!("Looping");
            thread::sleep(Duration::from_millis(500));

            if stop_bool.load(Ordering::Relaxed) {
                println!("Stopping");
                break;
            }
        }
    });

    self.running_thread_handles.push(handle);
}

这给了我这个错误:

错误:由于需求冲突,无法推断借用表达式的适当生命周期

我认为编译器不了解线程的生命周期,因为我所做的就是将句柄存储在一个向量中,所以我需要以某种方式告诉它,但是如何?

如果我声明这样的结构,我会越来越接近它的工作吗?

struct Test<'a> {
    should_stop: AtomicBool,
    running_thread_handles: &'a Vec<JoinHandle<()>>
}

我还有二次,相关的麻烦,我不能为我的生活弄清楚如何遍历我的句柄向量并在 Drop impl中调用它们上的任何函数 . 我想这个解决方案是相关的,所以我不会问 .

1 回答

  • 12

    有两种方法可以在线程之间访问变量:

    • 借用,这需要保证变量's lifetime exceeds the threads'的生命周期

    • 共享所有权(通过 Arc ):

    目前标准图书馆不支持借款,尽管第二方包装箱如crossbeam提供 . 对于共享所有权, Arc 确实是一种可能性......

    ...但是你需要仔细考虑你在_2859687中的内容:

    let stop_bool = Arc::new(&self.should_stop).clone();
    

    在这里,您正在从 &'a self 创建 Arc<&'a AtomicBool> ,因此您将通过借用的引用共享所有权 . 我将回到上面的解释:标准库中不支持跨线程借用 .

    您需要 Arc<AtomicBool> 才能获得正确的共享所有权,这可以通过更改 Test 来完成:

    struct Test {
        should_stop: Arc<AtomicBool>,
        running_thread_handles: Vec<JoinHandle<()>>
    }
    

    然后,克隆它很容易:

    let stop_bool = self.should_stop.clone();
    

相关问题