如何在一个线程中更新并从多个线程中读取?

How to update in one thread and read from many?

我没能通过借用检查器获取此代码:

use std::sync::Arc;
use std::thread::{sleep, spawn};
use std::time::Duration;

#[derive(Debug, Clone)]
struct State {
    count: u64,
    not_copyable: Vec<u8>,
}

fn bar(thread_num: u8, arc_state: Arc<State>) {
    let state = arc_state.clone();
    loop {
        sleep(Duration::from_millis(1000));
        println!("thread_num: {}, state.count: {}", thread_num, state.count);
    }
}

fn main() -> std::io::Result<()> {
    let mut state = State {
        count: 0,
        not_copyable: vec![],
    };
    let arc_state = Arc::new(state);

    for i in 0..2 {
        spawn(move || {
            bar(i, arc_state.clone());
        });
    }

    loop {
        sleep(Duration::from_millis(300));
        state.count += 1;
    }
}

我可能试错了。

我想要一个可以更新 state 的(主)线程和多个可以读取 state.

的线程

我应该如何在 Rust 中执行此操作?


我读过 the Rust book on shared state,但它使用的互斥量对于单个编写器/多个 reader 情况来说似乎过于复杂。

在 C 中,我会通过大量 _Atomic.

来实现这一点

Atomics 确实是一种正确的方法,std 中有很多这样的方法(link。您的示例需要 2 个修复。

  1. 在进入闭包之前 必须克隆 Arc ,因此您的循环变为:
for i in 0..2 {
    let arc_state = arc_state.clone();
    spawn(move || { bar(i, arc_state); });
}
  1. 使用 AtomicU64 相当简单,但您需要明确使用具有指定 Ordering (Playground) 的新类型方法):
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::thread::{sleep, spawn};
use std::time::Duration;

#[derive(Debug)]
struct State {
    count: AtomicU64,
    not_copyable: Vec<u8>,
}

fn bar(thread_num: u8, arc_state: Arc<State>) {
    let state = arc_state.clone();
    loop {
        sleep(Duration::from_millis(1000));
        println!(
            "thread_num: {}, state.count: {}",
            thread_num,
            state.count.load(Ordering::Relaxed)
        );
    }
}

fn main() -> std::io::Result<()> {
    let state = State {
        count: AtomicU64::new(0),
        not_copyable: vec![],
    };
    let arc_state = Arc::new(state);

    for i in 0..2 {
        let arc_state = arc_state.clone();
        spawn(move || {
            bar(i, arc_state);
        });
    }

    loop {
        sleep(Duration::from_millis(300));
        // you can't use `state` here, because it moved
        arc_state.count.fetch_add(1, Ordering::Relaxed);
    }
}