Rust 如何避免线程死机导致的死锁?
我的服务器使用Rust 如何避免线程死机导致的死锁?,rust,synchronization,deadlock,Rust,Synchronization,Deadlock,我的服务器使用屏障通知客户端何时可以安全地尝试连接。如果没有屏障,我们将面临随机失败的风险,因为无法保证服务器套接字会被绑定 现在假设服务器陷入恐慌——例如,试图将套接字绑定到端口80。客户端将永远处于等待状态。我们无法join()服务器线程以确定它是否惊慌失措,因为join()是一个阻塞操作-如果我们join()我们将无法connect() 如果std::syncapi不提供超时方法,那么进行这种同步的正确方法是什么 这只是一个演示问题的MCVE。我在一个单元测试中遇到了一个类似的情况——它一
屏障
通知客户端何时可以安全地尝试连接。如果没有屏障,我们将面临随机失败的风险,因为无法保证服务器套接字会被绑定
现在假设服务器陷入恐慌——例如,试图将套接字绑定到端口80。客户端将永远处于等待状态。我们无法join()
服务器线程以确定它是否惊慌失措,因为join()
是一个阻塞操作-如果我们join()
我们将无法connect()
如果std::sync
api不提供超时方法,那么进行这种同步的正确方法是什么
这只是一个演示问题的MCVE。我在一个单元测试中遇到了一个类似的情况——它一直在运行
use std::{
io::prelude::*,
net::{SocketAddr, TcpListener, TcpStream},
sync::{Arc, Barrier},
};
fn main() {
let port = 9090;
//let port = 80;
let barrier = Arc::new(Barrier::new(2));
let server_barrier = barrier.clone();
let client_sync = move || {
barrier.wait();
};
let server_sync = Box::new(move || {
server_barrier.wait();
});
server(server_sync, port);
//server(Box::new(|| { no_sync() }), port); //use to test without synchronisation
client(&client_sync, port);
//client(&no_sync, port); //use to test without synchronisation
}
fn no_sync() {
// do nothing in order to demonstrate the need for synchronization
}
fn server(sync: Box<Fn() + Send + Sync>, port: u16) {
std::thread::spawn(move || {
std::thread::sleep_ms(100); //there is no guarantee when the os will schedule the thread. make it 100% reproducible
let addr = SocketAddr::from(([127, 0, 0, 1], port));
let socket = TcpListener::bind(&addr).unwrap();
println!("server socket bound");
sync();
let (mut client, _) = socket.accept().unwrap();
client.write_all(b"hello mcve").unwrap();
});
}
fn client(sync: &Fn(), port: u16) {
sync();
let addr = SocketAddr::from(([127, 0, 0, 1], port));
let mut socket = TcpStream::connect(&addr).unwrap();
println!("client socket connected");
let mut buf = String::new();
socket.read_to_string(&mut buf).unwrap();
println!("client received: {}", buf);
}
使用std::{
io::前奏曲::*,
net::{SocketAddr,TcpListener,TcpStream},
同步::{Arc,Barrier},
};
fn main(){
设端口=9090;
//让端口=80;
让barrier=Arc::new(barrier::new(2));
让服务器_barrier=barrier.clone();
让客户端同步=移动{
等一下;
};
让服务器同步=框::新建(移动| |{
服务器_barrier.wait();
});
服务器(服务器同步,端口);
//服务器(Box::new(| |{no_sync()}),端口);//用于在不进行同步的情况下进行测试
客户端(&客户端同步,端口);
//客户端(&no_sync,port);//用于在不进行同步的情况下进行测试
}
fn no_sync(){
//不做任何事情来证明同步的必要性
}
fn服务器(同步:框,端口:u16){
std::thread::spawn(移动| |){
std::thread::sleep_ms(100);//无法保证操作系统何时调度线程。请使其100%可复制
让addr=SocketAddr::from([127,0,0,1],port));
让socket=TcpListener::bind(&addr).unwrap();
println!(“服务器套接字绑定”);
sync();
let(mut client,z)=socket.accept().unwrap();
client.write_all(b“hello mcve”).unwrap();
});
}
fn客户端(同步:&fn(),端口:u16){
sync();
让addr=SocketAddr::from([127,0,0,1],port));
让mut socket=TcpStream::connect(&addr).unwrap();
println!(“已连接客户端套接字”);
让mut buf=String::new();
socket.read_to_string(&mut buf).unwrap();
println!(“收到的客户:{}”,buf);
}
我会在这里使用一个障碍物,而不是障碍物
要真正解决您的问题,我至少看到三种可能的解决方案:
使用并将超时设置为合理的持续时间(例如,1秒,该时间应足以绑定到端口)
您可以使用与上面相同的方法,但超时时间较短(例如10毫秒),并检查Mutex
是否中毒
您可以使用普通(确保互斥体
首先被另一个线程锁定),然后使用来检查互斥体
我认为应该选择解决方案1或2而不是第三个,因为您将避免确保另一个线程首先锁定了互斥锁