【问题标题】:Is this because the mutex was not released?这是因为没有释放互斥锁吗?
【发布时间】:2023-02-07 09:13:23
【问题描述】:

我读过这个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 会导致这种情况。

但我不明白为什么我上面的代码也会导致这种情况。

谁能给我答案。

【问题讨论】:

  • 我发现if let Ok(job) = rx.lock().unwrap().recv(){ job(); }会导致与rx.lock().unwrap().recv().unwrap()();相同的事情

标签: rust threadpool mutex


【解决方案1】:

在 Rust 中,临时对象被丢弃在包含它们的表达式的末尾(这里有一些 caveats 不相关)。

而我们感兴趣的temporary是mutex的guard,他的drop负责释放mutex锁。

所以,明确地写下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() 函数,但互斥量仍处于锁定状态。

【讨论】:

    【解决方案2】:

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

    是的,你基本上是这样做的

    {
        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(),同时仍然持有锁,这会阻塞当前线程(进入休眠状态),直到有东西被发送到通道中。但是考虑到如果通道上没有作业,一个线程只会阻塞其他线程,我想这是设计使然。

    【讨论】:

    • 关于recv上的阻塞,嗯,是一个mpsc,也就是多生产者,单一消费者频道:你不能让多个线程同时接收。
    • 是的,我同意,只是想指出,对于短期任务,大多数线程将花费时间来争夺锁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-17
    • 2010-12-25
    • 2012-02-23
    • 1970-01-01
    • 2012-06-05
    • 2017-02-23
    • 1970-01-01
    相关资源
    最近更新 更多