首页 > 解决方案 > 如何在一个线程中更新并从多个线程中读取?

问题描述

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

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 中做到这一点?


我已经阅读了关于共享状态的 Rust 书,但是它使用了互斥锁,对于单个写入器/多个读取器的情况来说,这似乎过于复杂。

在 CI 中,通过大量的_Atomic.

标签: multithreadingrustborrow-checker

解决方案


原子确实是一种正确的方法,在 std (链接。您的示例需要 2 个修复。

  1. 在进入闭包之前必须克隆 Arc ,因此您的循环变为:
for i in 0..2 {
    let arc_state = arc_state.clone();
    spawn(move || { bar(i, arc_state); });
}
  1. 使用AtomicU64是相当直接的,尽管您需要明确使用指定OrderingPlayground)的 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);
    }
}

推荐阅读