简体   繁体   English

实现“移动”线程语义

[英]Implementing “move” thread semantics

I want to write a function to be called like this: 我想编写一个这样的函数:

send("message","address");

Where some other thread that is doing 其他一些线程正在做什么

let k = recv("address");
println!("{}",k);

sees message . 看到message

In particular, the message may be large, and so I'd like "move" or "zero-copy" semantics for sending the message. 特别是,消息可能很大,因此我想使用“ move”或“ zero-copy”语义发送消息。

In C, the solution is something like: 在C语言中,解决方案类似于:

  1. Allocate messages on the heap 在堆上分配消息
  2. Have a global, threadsafe hashmap that maps "address" to some memory location 有一个全局的,线程安全的哈希映射,可将“地址”映射到某些内存位置
  3. Write pointers into the memory location on send, and wake up the receiver using a semaphore 在发送时将指针写入存储位置,并使用信号量唤醒接收器
  4. Read pointers out of the memory location on receive, and wait on a semaphore to process new messages 在接收时从内存位置中读取指针,然后等待信号量以处理新消息

But according to another SO question, step #2 " sounds like a bad idea ". 但是根据另一个SO问题,步骤2“ 听起来像是个坏主意 ”。 So I'd like to see a more Rust-idiomatic way to approach this problem. 因此,我希望看到一种更符合Rust习惯的方法来解决此问题。

You get these sort of move semantics automatically, and get achieve light-weight moves by placing large values into a Box (ie allocate them on the heap). 您会自动获得这种移动语义,并通过将较大的值放入Box (即在堆上分配它们)来实现轻量级的移动。 Using type ConcurrentHashMap<K, V> = Mutex<HashMap<K, V>>; 使用type ConcurrentHashMap<K, V> = Mutex<HashMap<K, V>>; as the threadsafe hashmap (there's various ways this could be improved), one might have: 作为线程安全的哈希表(可以通过多种方式进行改进),其中一个可能具有:

use std::collections::{HashMap, RingBuf};
use std::sync::Mutex;

type ConcurrentHashMap<K, V> = Mutex<HashMap<K, V>>;

lazy_static! {
    pub static ref MAP: ConcurrentHashMap<String, RingBuf<String>> = {
        Mutex::new(HashMap::new())
    }
}

fn send(message: String, address: String) {
    MAP.lock()
       // find the place this message goes
       .entry(address)
       .get()
       // create a new RingBuf if this address was empty
       .unwrap_or_else(|v| v.insert(RingBuf::new()))
       // add the message on the back
       .push_back(message)
}
fn recv(address: &str) -> Option<String> {
     MAP.lock()
        .get_mut(address)
        // pull the message off the front
        .and_then(|buf| buf.pop_front())
}

That code is using the lazy_static! 该代码正在使用lazy_static! macro to achieve a global hashmap (it may be better to use a local object that wraps an Arc<ConcurrentHashMap<...> , fwiw, since global state can make reasoning about program behaviour hard). 宏以实现全局哈希图(最好使用包装Arc<ConcurrentHashMap<...> fwiw的本地对象,因为全局状态会使对程序行为的推理变得困难)。 It also uses RingBuf as a queue, so that messages bank up for a given address . 它还将RingBuf用作队列,以便消息为给定address堆积。 If you only wish to support one message at a time, the type could be ConcurrentHashMap<String, String> , send could become MAP.lock().insert(address, message) and recv just MAP.lock().remove(address) . 如果您一次只希望支持一条消息,则类型可以为ConcurrentHashMap<String, String>send可以成为MAP.lock().insert(address, message)并仅recv MAP.lock().remove(address)

(NB. I haven't compiled this, so the types may not match up precisely.) (注意。我尚未编译此文件,因此类型可能不完全匹配。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM