rust 这是因为互斥锁没有被释放吗?

nnt7mjpx  于 2023-02-08  发布在  其他
关注(0)|答案(2)|浏览(161)

我读过这个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会导致这种情况。
但是我不明白为什么我上面的代码也会导致这样的结果。
谁能给我答案。

bqf10yzr

bqf10yzr1#

在Rust中,临时对象在包含它们的表达式末尾被丢弃(这里有一些不相关的警告)。
我们感兴趣的临时变量是互斥锁的守护变量,它的drop负责释放互斥锁。
因此,显式地编写drop,您的第一个代码是:

let job = rx.lock().unwrap().recv().unwrap();
job();

相当于:

let mut guard = rx.lock().unwrap();
let job = guard.recv().unwrap();
drop(guard);
job();

你的第二个密码:

rx.lock().unwrap().recv().unwrap()();

相当于:

let mut guard = rx.lock().unwrap();
let job = guard.recv().unwrap()
job();
drop(guard);

如您所见,现在调用job()函数时互斥锁仍然锁定。

zpgglvta

zpgglvta2#

这是因为互斥锁没有被释放吗?
是的,你基本上是这样做的

{
    let rx = rx.lock().unwrap(); // got the lock
    let job = rx.recv().unwrap(); // got the job
    // going to sleep while still holding mutex lock
    job(); // std::thread::sleep(Duration::from_secs(5))
    drop(rx); // lock is released
}

由于所有线程都共享互斥锁,并且将尝试获取锁,因此它们实际上被阻塞,直到带锁的休眠线程被唤醒。这就是为什么在请求sleep端点后,其他线程无法执行任何其他作业。
然而还有另一个问题。即使它没有休眠,它仍然在持有锁的同时调用Receiver::recv(),这会阻塞当前线程(进入休眠),直到有东西发送到通道。但是考虑到一个线程只有在通道上没有作业时才会阻塞其他线程,我猜这是设计好的。

相关问题