1

我想在 rust 中实现一个多路复用器/解复用器。它应该DuplexStream通过一个单一的“下游”发送多个“上游”的数据,DuplexStream只需port_num将上游的标识符添加DuplexStream到数据包中即可。当然,这也应该反过来工作:port_num从从下游接收的数据包中读取数据并将其发送到正确的上游流。

我开始实现这样的MultiplexStream(下面的代码不会编译)。但是,我面临一个问题:映射到相应上游的open_ports变量必须可以被多个任务访问,这在 Rust 中是不允许的。port_numDuplexStream

在这里可以应用什么设计模式来解决我的问题?

impl MultiplexStream<T,U> {
    fn new(downstream: DuplexStream<(u32,T), U>) -> MultiplexStream<T,U> {
        let mut open_ports = HashMap::<u32, DuplexStream<(u32,T), U>>new();

        spawn do {
            let res = try {
                loop {
                    let (port_num, data) = downstream.recv();

                    match open_ports.find(port_num) {
                        Some(intermediate) => {
                            let res = try {
                                intermediate.send(data)
                            }

                            if res.is_err() {
                                open_ports.remove(port_num);
                            }
                        }
                        None => {}
                    }
                }
            }

            // downstream was closed => cleanup
            for intermediate in open_ports.values() {
                intermediate.close();
            }
            open_ports.clear();
        }

    }

    fn open<V: Send>(port_num: u32) -> Result(DuplexStream<V,T>, ()) {
        if open_ports.contains_key(port_num) {
            return Err(());
        }

        let (upstream, intermediate) = DuplexStream<V,T>::new();
        open_ports.insert(port_num, intermediate);

        spawn do {
            let res = try {
                loop {
                    let data = intermediate.recv();
                    downstream.send(~(port_num, data));
                }
            }

            // upstream was closed => cleanup
            intermediate.close();
            open_ports.remove(port_num);
        }

        return Ok(upstream);
    }
}
4

1 回答 1

2

在 rust 中,共享数据是通过 Arc(来自 libsync)完成的。Basic Arc 用于共享不可变数据,可变数据有 MutexArc 和 RWArc。与 Arc 共享是免费的。

我整理了一个小例子:

extern mod sync;

use std::hashmap::HashMap;

fn main() {
    let arc = sync::RWArc::new(HashMap::<~str, int>::new());
    arc.write(|m| m.insert(~"a", 0));
    for num in range(1, 10) {
        let arc = arc.clone();
        spawn(proc() {
            println!("[task {}] Value before is: {}", num, arc.read(|m| m.get(&~"a").clone()));
            arc.write(|m| { m.insert_or_update_with(~"a", 0, |_, val| *val += 1); });
            println!("[task {}] Value after is: {}", num, arc.read(|m| m.get(&~"a").clone()));
        });
    }
}

对于最新版本的 rust (0.10pre) 使用

extern crate collections;
extern crate sync;
use collections::hashmap::HashMap;
use sync::RWArc;

fn main() {
    let arc = RWArc::new(HashMap::<~str, int>::new());
    arc.write(|m| m.insert(~"a", 0));
    for num in range(1, 10) {
        let arc = arc.clone();
        spawn(proc() {
            println!("[task {}] Value before is: {}", num, arc.read(|m| m.get(&~"a").clone()));
            arc.write(|m| { m.insert_or_update_with(~"a", 0, |_, val| *val += 1); });
            println!("[task {}] Value after is: {}", num, arc.read(|m| m.get(&~"a").clone()));
        });
    }
}
于 2014-02-20T18:17:04.890 回答