我试图并行运行两个线程,并在它们之间共享一些数据。当其中一个线程包含循环语句时,另一个线程中的共享数据将进入死锁状态。
但是,如果我在代码中添加一行代码,以便在经过一定次数的迭代后跳出loop
语句,那么死锁就会被释放,下一个线程中的操作就会开始。
Rust Playground
代码:
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
#[derive(Clone, Copy)]
struct SomeNetwork {
is_connected: bool,
}
impl SomeNetwork {
fn connection_manager(&mut self) {
loop {
// if I exit the loop after a few iterations then the deadlock is removed
// eg: when I use `for i in 0..10 {` instead of `loop`
println!("connection_manager thread...");
thread::sleep(Duration::from_millis(2000));
}
}
fn api_calls(&self) {
loop {
if self.is_connected {
//make_an_api_call()
}
println!("api_calls thread...");
thread::sleep(Duration::from_millis(5000));
}
}
pub fn start() {
let self_arc = SomeNetwork {
is_connected: false,
};
let self_arc = Arc::new(Mutex::new(self_arc));
let self_cloned1 = Arc::clone(&self_arc);
let self_cloned2 = Arc::clone(&self_arc);
thread::Builder::new()
.spawn(move || {
let mut n = self_cloned1.lock().unwrap();
n.connection_manager();
})
.unwrap();
thread::Builder::new()
.spawn(move || {
let n = self_cloned2.lock().unwrap(); // <---- deadlock here
n.api_calls();
})
.unwrap();
loop {
thread::sleep(Duration::from_millis(5000))
}
}
}
fn main() {
SomeNetwork::start();
}
输出:
connection_manager thread...
connection_manager thread...
connection_manager thread...
connection_manager thread...
connection_manager thread...
....
一旦线程进入睡眠状态,底层操作系统不会负责调度吗?
这里可以做些什么,以便我可以并行运行两个线程?
1条答案
按热度按时间i2loujxw1#
问题是您创建的互斥锁在
connection_manager
期间保持锁定。在Rust中使用互斥锁的方式是它 Package 它锁定的数据,当你锁定互斥锁时,它会阻塞当前线程,直到它能够获得互斥锁为止,一旦它获得了,它给你一个
MutexGuard
,你可以把它看作是一个互斥体引用的 Package 器,MutexGuard
给你一个对互斥体内部数据的可变访问。然后,一旦不再需要MutexGuard
,Rust调用MutexGuard
的Drop
实现,它解锁互斥锁并允许其他线程获得它。如您所见,如果
connection_manager
从未退出,则互斥锁将保持锁定状态,直到第一个线程获得互斥锁。您可能需要将互斥锁与condvar一起使用,以便在线程休眠时释放互斥锁。
下面是使用condvar处理连接和使用通道将作业传递给工作线程的大致概念。Playground Link