multithreading - 在Rust中的线程之间共享可变数据

标签 multithreading rust

我知道像这个问题一样有数百个问题,但是我很难理解如何做我想做的事情。
我想要一个接受和处理事件的http服务器。在接收/处理事件时,我希望EventManager将更新发送到ApplicationMonitor,以跟踪已接受/处理了多少事件。 ApplicationMonitor还将(最终)处理诸如跟踪并发连接数之类的事情,但是在此示例中,我只希望EventManagerInc('event_accepted')更新发送到我的ApplicationMonitor
为了有用,我需要ApplicationMonitor才能通过/stats路由请求返回统计信息的快照。
enter image description here
所以我有一个ApplicationMonitor,它产生一个线程并在 channel 上监听传入的Stat事件。收到Stat事件时,它将更新统计信息HashMap。统计信息哈希图在ApplicationMonitor和生成的线程中都必须是可变的。

use std::sync::mpsc;
use std::sync::mpsc::Sender;
use std::thread;
use std::thread::JoinHandle;
use std::collections::HashMap;

pub enum Stat {
    Inc(&'static str),
    Dec(&'static str),
    Set(&'static str, i32)
}

pub struct ApplicationMonitor {
    pub tx: Sender<Stat>,
    pub join_handle: JoinHandle<()>
}

impl ApplicationMonitor {
    pub fn new() -> ApplicationMonitor {
        let (tx, rx) = mpsc::channel::<Stat>();

        let mut stats: HashMap<&'static str, i32> = HashMap::new();

        let join_handle = thread::spawn(move || {
            for stat in rx.recv() {
                match stat {
                    Stat::Inc(nm) => {
                        let current_val = stats.entry(nm).or_insert(0);
                        stats.insert(nm, *current_val + 1);
                    },
                    Stat::Dec(nm) => {
                        let current_val = stats.entry(nm).or_insert(0);
                        stats.insert(nm, *current_val - 1);
                    },
                    Stat::Set(nm, val) => {
                        stats.insert(nm, val);
                    }
                }
            }
        });

        let am = ApplicationMonitor {
            tx,
            join_handle
        };

        am
    }

    pub fn get_snapshot(&self) -> HashMap<&'static str, i32> {
        self.stats.clone()
    }
}
由于无法克隆rx,因此必须将引用move放入闭包中。当我这样做时,我将不再能够在线程之外访问stats
我以为可能需要第二个 channel ,以便线程可以回传其内部信息,但这是行不通的,因为我需要另一个线程以非阻塞方式进行监听。
这是我要使用Arc的地方吗?
如何让stats在线程上下文内外存在?

最佳答案

是的,这是将stats包装在Arc中的地方,以便可以从不同线程对其进行多个引用。但是只包装Arc只会给您HashMap的只读 View -如果您需要对其进行修改,则还需要将其包装在某种东西中,以确保在同一时间只能修改一件事。时间。因此,您可能最终会得到Arc<Mutex<HashMap<&'static str, i32>>>Arc<RwLock<HashMap<&'static str, i32>>>
另外,如果您只是更改值,而不添加或删除值,则可以使用Arc<HashMap<&static str, AtomicU32>>,它允许您并行读取和修改不同的值,而无需取出整个Map范围的锁定,但需要Atomic与锁相比,s更容易理解和正确使用。

关于multithreading - 在Rust中的线程之间共享可变数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63102930/

相关文章:

java - 等待多个 SwingWorker

python - PySerial 丢失数据

c - 为什么 pthread_join 在最后一次迭代中失败(给出段错误)?

c++ - 是否有任何不关注 Java 的优秀并发/并行书籍?

java - 我应该把工作线程放在哪里

rust - 为什么借用会阻止在数组访问中内联函数调用?

json - 如何编写 Serde Visitor 将字符串数组转换为 Vec<Vec<f64>>?

enums - 我可以使用枚举作为另一个枚举的值检查器吗?

static - 如何在没有赋值的情况下声明静态可变变量?

rust - 借用“self”问题