【问题标题】:How to update in one thread and read from many?如何在一个线程中更新并从多个线程中读取?
【发布时间】:2020-07-07 21:06:26
【问题描述】:

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

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,但它使用的互斥锁对于单个写入器/多个读取器的情况来说似乎过于复杂。

在 C 语言中,我会通过大量的 _Atomic 来实现这一点。

【问题讨论】:

    标签: multithreading rust borrow-checker


    【解决方案1】:

    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) 的newtype 方法:
    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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多