我读过这个Turning Our Single-Threaded Server into a Multithreaded Server,并试着实现它。
我写了这个:
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
type task = dyn FnOnce() + Send + 'static;
pub struct Threadpool {
threads: Vec<thread::JoinHandle<()>>,
rx: Arc<Mutex<Receiver<Box<task>>>>,
tx: Sender<Box<task>>,
}
impl Threadpool {
pub fn new(size: usize) -> Threadpool {
let mut tasks = Vec::with_capacity(size);
let (tx, rx): (Sender<Box<task>>, Receiver<Box<task>>) = channel();
let rx = Arc::new(Mutex::new(rx));
for _ in 0..size {
let rx = rx.clone();
let task = thread::spawn(move || {
loop {
let job= rx.lock().unwrap().recv().unwrap();
job();
}
});
tasks.push(task);
}
Threadpool {
threads: tasks,
rx,
tx,
}
}
pub fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
self.tx.send(Box::new(f)).unwrap();
}
}
它起作用了。
但当我改变
let job= rx.lock().unwrap().recv().unwrap();
job();
到
rx.lock().unwrap().recv().unwrap()();
当我打开localhost:port/sleep
,然后打开localhost:port
时,需要5秒钟。
我把它设为主模式
"GET /sleep HTTP/1.1" => {
thread::sleep(Duration::from_secs(5));
("HTTP/1.1 200 OK", "hello.html")
}
我已经知道while let
会导致这种情况。
但是我不明白为什么我上面的代码也会导致这样的结果。
谁能给我答案。
2条答案
按热度按时间bqf10yzr1#
在Rust中,临时对象在包含它们的表达式末尾被丢弃(这里有一些不相关的警告)。
我们感兴趣的临时变量是互斥锁的守护变量,它的
drop
负责释放互斥锁。因此,显式地编写
drop
,您的第一个代码是:相当于:
你的第二个密码:
相当于:
如您所见,现在调用
job()
函数时互斥锁仍然锁定。zpgglvta2#
这是因为互斥锁没有被释放吗?
是的,你基本上是这样做的
由于所有线程都共享互斥锁,并且将尝试获取锁,因此它们实际上被阻塞,直到带锁的休眠线程被唤醒。这就是为什么在请求
sleep
端点后,其他线程无法执行任何其他作业。然而还有另一个问题。即使它没有休眠,它仍然在持有锁的同时调用
Receiver::recv()
,这会阻塞当前线程(进入休眠),直到有东西发送到通道。但是考虑到一个线程只有在通道上没有作业时才会阻塞其他线程,我猜这是设计好的。