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

kmp*_*kmp 5 multithreading rust

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

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();
}
Run Code Online (Sandbox Code Playgroud)

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

我以为我需要的只是一个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);
}
Run Code Online (Sandbox Code Playgroud)

这给了我这个错误:

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

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

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

struct Test<'a> {
    should_stop: AtomicBool,
    running_thread_handles: &'a Vec<JoinHandle<()>>
}
Run Code Online (Sandbox Code Playgroud)

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

see*_*per 16

我在这里发布我自己的答案,希望提供一个清晰的通用示例,因为接受的答案非常具体于原始问题,让我有点不确定如何做到这一点:

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

fn main() {
  let stop = Arc::new(AtomicBool::new(false)); 
  let stop_me = stop.clone();
  thread::spawn(move || {
      let mut i = 0;
      loop {
          i = i + 1;
          if stop_me.load(Ordering::Relaxed) {
              println!("iterations = {}", i);
              break;
          }
          if i % 1000000 == 0 {
              println!("Another million iterations down...");
          }
      }
  });
  let delay = time::Duration::from_millis(100);
  thread::sleep(delay);
  stop.store(true, Ordering::Relaxed);
  println!("All done");
}
Run Code Online (Sandbox Code Playgroud)

Rust 游乐场链接:https://play.rust-lang.org/?version =stable&mode=debug&edition=2018&gist=4a36363b361b5b933d9e70989a18d67a


Mat*_* M. 13

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

  • 借用,这需要保证变量的生命周期超过线程的生命周期
  • 共享所有权(via Arc):

目前标准图书馆不支持借款,但横梁等第三方板条箱提供借款.对于共享所有权,Arc确实是一种可能性......

...但是你需要Arc仔细考虑你所放的东西:

let stop_bool = Arc::new(&self.should_stop).clone();
Run Code Online (Sandbox Code Playgroud)

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

您需要一个Arc<AtomicBool>适当的共享所有权,这可以通过更改Test:

struct Test {
    should_stop: Arc<AtomicBool>,
    running_thread_handles: Vec<JoinHandle<()>>
}
Run Code Online (Sandbox Code Playgroud)

然后,克隆它很容易:

let stop_bool = self.should_stop.clone();
Run Code Online (Sandbox Code Playgroud)

  • 这些年来这种情况有变化吗?无法轻松地跨线程共享 AtomicBool 是……好吧,太糟糕了。这是重点,因此必须将其包装在 Arc 等其他类型中并不是一种很好的体验。 (2认同)