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而不是第三个,因为您将避免确保另一个线程首先锁定了
    互斥锁