gpt4 book ai didi

rust - 如何避免线程 panic 导致的死锁?

转载 作者:行者123 更新时间:2023-11-29 08:15:33 24 4
gpt4 key购买 nike

我的服务器使用 Barrier 来通知客户端何时可以安全地尝试连接。如果没有屏障,我们可能会随机失败,因为无法保证服务器套接字会被绑定(bind)。

现在想象一下,服务器发生 panic - 例如试图将套接字绑定(bind)到端口 80。客户端将永远处于 wait() 状态。我们不能 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);
}

最佳答案

我会使用 Condvar 而不是 Barrier在这里。

要真正解决您的问题,我至少看到了三种可能的解决方案:

  1. 使用Condvar::wait_timeout并将超时设置为合理的持续时间(例如 1 秒,这应该足以绑定(bind)到端口)
  2. 您可以使用与上述相同的方法,但超时时间较短(例如 10 毫秒)并检查 Mutex 是否中毒。
  3. 您可以使用普通的 Mutex 而不是 Condvar (确保 Mutex 首先被另一个线程锁定)然后使用 Mutex::try_lock检查是否 Mutex is poisoned

我认为相比第三种,我认为应该更喜欢解决方案 1 或 2,因为您将避免确保另一个线程首先锁定了 Mutex

关于rust - 如何避免线程 panic 导致的死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55280339/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com