如何创建可以在 Rust 多线程服务器中使用的结构?
Posted
技术标签:
【中文标题】如何创建可以在 Rust 多线程服务器中使用的结构?【英文标题】:How do I create a structure that can be used in a Rust multithreaded server? 【发布时间】:2016-11-03 07:01:48 【问题描述】:我想实现一个简单的服务器,供我项目的 3 个不同模块使用。 这些模块会将数据发送到服务器,服务器会将其保存到文件中,并在这些模块完成工作时合并这些信息。 所有这些信息都有一个时间戳(一个浮点数)和一个标签(一个浮点数或一个字符串)。
这是我保存这些信息的数据结构:
pub struct Data
file_name: String,
logs: Vec<(f32, String)>,
measures: Vec<(f32, f32)>,
statements: Vec<(f32, String)>,
我使用socket
与服务器交互。
我还使用 Arc
来实现 Data
结构并使其可被每个模块共享。
所以,当我处理客户端时,我会验证模块发送的消息是否正确,如果是,我会调用一个新函数来处理并将消息保存在良好的数据结构字段(logs
、measures
或statements
)。
// Current ip address
let ip_addr: &str = &format!(":",
&ip,
port);
// Bind the current IP address
let listener = match TcpListener::bind(ip_addr)
Ok(listener) => listener,
Err(error) => panic!("Canno't bind , due to error ",
ip_addr,
error),
;
let global_data_struct = Data::new(DEFAULT_FILE.to_string());
let global_data_struct_shared = Arc::new(global_data_struct);
// Get and process streams
for stream in listener.incoming()
let mut global_data_struct_shared_clone = global_data_struct_shared.clone();
thread::spawn(move ||
// Borrow stream
let stream = stream;
match stream
// Get the stream value
Ok(mut stream_v) =>
let current_ip = stream_v.peer_addr().unwrap().ip();
let current_port = stream_v.peer_addr().unwrap().port();
println!("Connected with peer :", current_ip, current_port);
// PROBLEM IN handle_client!
// A get_mut from global_data_struct_shared_clone
// returns to me None, not a value - so I
// can't access to global_data_struct_shared_clone
// fields :'(
handle_client(&mut stream_v, &mut global_data_struct_shared_clone);
,
Err(_) => error!("Canno't decode stream"),
);
// Stop listening
drop(listener);
我在获取handle_client
中的可变引用以处理global_data_struct_shared_clone
中的字段时遇到了一些问题,因为Arc::get_mut(global_data_struct_shared_clone)
返回给我None
- 由于每个传入请求的global_data_struct_shared.clone()
。
有人可以帮我正确管理这 3 个模块之间的结构吗?
【问题讨论】:
您尝试过使用Arc<Mutex<...>>
吗?
不,因为我认为使用Mutex
会遇到问题,特别是因为我的任何模块都不会访问模块已经存在的字段。每个模块在Data
中都有自己的字段 - 所以将Mutex
给Arc
将无用地阻止我的结构,对吧...?
它只在处理时阻塞,但你可以用更精细的方式完美地做到这一点:)
好的,我会试试的,谢谢 :-) 如果可行,我会发布解决方案。
好的,我尝试将Mutex
与Arc
一起使用,它似乎有效!下一级:粒度...再次非常感谢 ;-)
【参考方案1】:
Rust 的见解是,内存安全是通过强制执行 Aliasing XOR Mutability 来实现的。
执行这一单一原则可以防止所有类别的错误:指针/迭代器失效(这是目标)以及数据竞争。
Rust 将尽可能在编译时强制执行这一原则;但是,如果用户使用专用类型/方法选择加入,它也可以在运行时强制执行。
Arc::get_mut
就是这样一种方法。 Arc
(原子引用计数指针)专门用于在多个所有者之间共享引用,这意味着别名,因此默认情况下不允许可变性; Arc::get_mut
将执行运行时检查:如果指针实际上不是别名(计数为 1),则它允许可变性。
但是,正如您所意识到的,这不适合您的情况,因为 Arc
在那个时间点是别名。
所以你需要转向其他类型。
最简单的解决方案是Arc<Mutex<...>>
,Arc
允许共享,Mutex
允许受控可变性,您可以与Mutex
强制执行的运行时受控可变性一起共享。
这是粗粒度的,但可能就足够了。
更复杂的方法可以使用RwLock
(读写锁),更细粒度的Mutex
甚至原子;但我建议从一个 Mutex
开始,看看效果如何,你必须先走路再跑。
【讨论】:
以上是关于如何创建可以在 Rust 多线程服务器中使用的结构?的主要内容,如果未能解决你的问题,请参考以下文章