如何使用Condvar限制多线程?

Dum*_*les 5 multithreading rust

我正在尝试使用a Condvar来限制在任何给定时间处于活动状态的线程数.我很难找到如何使用的好例子Condvar.到目前为止,我有:

use std::sync::{Arc, Condvar, Mutex};
use std::thread;

fn main() {
    let thread_count_arc = Arc::new((Mutex::new(0), Condvar::new()));
    let mut i = 0;
    while i < 100 {
        let thread_count = thread_count_arc.clone();
        thread::spawn(move || {
            let &(ref num, ref cvar) = &*thread_count;
            {
                let mut start = num.lock().unwrap();
                if *start >= 20 {
                    cvar.wait(start);
                }
                *start += 1;
            }
            println!("hello");
            cvar.notify_one();
        });
        i += 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

给出的编译器错误是:

error[E0382]: use of moved value: `start`
  --> src/main.rs:16:18
   |
14 |                     cvar.wait(start);
   |                               ----- value moved here
15 |                 }
16 |                 *start += 1;
   |                  ^^^^^ value used here after move
   |
   = note: move occurs because `start` has type `std::sync::MutexGuard<'_, i32>`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

我完全不确定我的使用Condvar是否正确.我尝试尽可能接近Rust API上的示例.Wwat是实现这个的正确方法吗?

She*_*ter 4

这是一个可以编译的版本:

use std::{
    sync::{Arc, Condvar, Mutex},
    thread,
};

fn main() {
    let thread_count_arc = Arc::new((Mutex::new(0u8), Condvar::new()));
    let mut i = 0;
    while i < 100 {
        let thread_count = thread_count_arc.clone();
        thread::spawn(move || {
            let (num, cvar) = &*thread_count;

            let mut start = cvar
                .wait_while(num.lock().unwrap(), |start| *start >= 20)
                .unwrap();

            // Before Rust 1.42, use this:
            //
            // let mut start = num.lock().unwrap();
            // while *start >= 20 {
            //     start = cvar.wait(start).unwrap()
            // }

            *start += 1;

            println!("hello");
            cvar.notify_one();
        });
        i += 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

Condvar::wait_while重要的部分可以从or的签名看出Condvar::wait

pub fn wait_while<'a, T, F>(
    &self,
    guard: MutexGuard<'a, T>,
    condition: F
) -> LockResult<MutexGuard<'a, T>>
where
    F: FnMut(&mut T) -> bool, 
Run Code Online (Sandbox Code Playgroud)
pub fn wait<'a, T>(
    &self,
    guard: MutexGuard<'a, T>
) -> LockResult<MutexGuard<'a, T>>
Run Code Online (Sandbox Code Playgroud)

这表示wait_while/wait 消耗guard,这就是为什么你会得到你所做的错误 - 你不再拥有start,所以你不能调用它的任何方法!

这些函数很好地反映了 s 的工作原理- 您暂时放弃了( 由 表示)Condvar上的锁定,当函数返回时,您再次获得锁定。Mutexstart

解决方法是放弃锁,然后从wait_while/获取锁防护返回值wait在 huon 的鼓励下,我也从 an 切换if到 a 。while