如果執行緒正在休眠,正在等待 notify_one / notify_all 呼叫,但在此之前執行緒被喚醒,是呼叫 wait 回傳還是執行緒繼續等待?
我已經閱讀了檔案(針對 Condvar::wait),我不清楚這是否意味著一旦喚醒執行緒就會回傳等待呼叫:
請注意,此功能容易受到虛假喚醒的影響。條件變數通常有一個與之關聯的布爾謂詞,并且每次該函式回傳時都必須檢查謂詞以防止虛假喚醒。
如果是執行緒一被喚醒就呼叫wait,那么回傳的是什么?因為它必須回傳某種守衛:
pub type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;
具體例子,特別是recv方法:
pub struct Receiver<T> {
shared: Arc<Shared<T>>
}
impl<T> Receiver<T> {
pub fn recv(&self) -> Option<T> {
let mut inner_mutex_guard:MutexGuard<Inner<T>> = self.shared.inner.lock().unwrap();
loop {
match inner_mutex_guard.queue.pop_front() {
Some(t) => return Some(t),
None => {
if inner_mutex_guard.senders == 0 {
return None
} else {
inner_mutex_guard = Condvar::wait(&self.shared.available, inner_mutex_guard).unwrap();
}
}
}
}
}
}
pub struct Inner<T> {
queue: VecDeque<T>,
senders: usize
}
pub struct Shared<T> {
inner: Mutex<Inner<T>>,
available: Condvar,
}
uj5u.com熱心網友回復:
你的例子是正確的。雖然我會寫
inner_mutex_guard = self.shared.available.wait(inner_mutex_guard).unwrap();
代替
inner_mutex_guard = Condvar::wait(&self.shared.available, inner_mutex_guard).unwrap();
如果發生虛假喚醒,您的回圈將pop_front()再次呼叫,這可能會回傳None并進入另一個.wait().
我了解您可能對Condition variables normally have a boolean predicate associated with them. 那是因為你的布爾謂詞有點隱藏......它是"Does .pop_front()return Some"。每當發生喚醒時,您都會根據需要進行檢查。
的回傳型別.wait()是 another LockGuard。為了使某些事情發生,其他人必須有可能更改鎖定的值。因此,必須在等待時解鎖該值。
由于在 的實作中有幾個容易錯過的競爭條件unlock-wait-lock,它通常在一次呼叫中完成。所以.wait()解鎖該值,等待條件發生,然后再次鎖定該值。這就是為什么它回傳一個新的LockGuard......它是新的鎖定和可能更改的值。
雖然說實話,我不確定他們為什么這樣做……他們也可以這樣做.wait(&mut LockGuard)而不是.wait(LockGuard) -> LockGuard. 但誰知道呢。
編輯:我很確定他們會回傳一個鎖衛,因為重新鎖定可能會失敗;因此他們實際上并沒有回傳 aLockGuard而是 aResult<LockGuard>
編輯#2:它不能通過參考傳遞,因為在等待期間,不LockGuard存在。前一個被洗掉了,新的只有在資料再次被鎖定時才存在。并且LockGuard沒有“空”狀態(如None),因此它實際上必須被消耗和丟棄。參考是不可能的。
的解釋CondVar
?添加示例之前的原始答案?
您必須了解 aCondVar更多的是一種優化。它可以防止空閑等待條件。這就是為什么它需要 a 的原因Guard,它應該與您想要監視更改的鎖定值結合使用。因此,如果它喚醒,請檢查值是否已更改,然后回傳wait. wait意味著在回圈中呼叫。
這是一個例子:
use std::{
sync::{Arc, Condvar, Mutex},
thread::{sleep, JoinHandle},
time::Duration,
};
struct Counter {
value: Mutex<u32>,
condvar: Condvar,
}
fn start_counting_thread(counter: Arc<Counter>) -> JoinHandle<()> {
std::thread::spawn(move || loop {
sleep(Duration::from_millis(100));
let mut value = counter.value.lock().unwrap();
*value = 1;
counter.condvar.notify_all();
if *value > 15 {
break;
}
})
}
fn main() {
let counter = Arc::new(Counter {
value: Mutex::new(0),
condvar: Condvar::new(),
});
let counting_thread = start_counting_thread(counter.clone());
// Wait until the value more than 10
let mut value = counter.value.lock().unwrap();
while *value <= 10 {
println!("Value is {value}, waiting ...");
value = counter.condvar.wait(value).unwrap();
}
println!("Condition met. Value is now {}.", *value);
// Unlock value
drop(value);
// Wait for counting thread to finish
counting_thread.join().unwrap();
}
Value is 0, waiting ...
Value is 1, waiting ...
Value is 2, waiting ...
Value is 3, waiting ...
Value is 4, waiting ...
Value is 5, waiting ...
Value is 6, waiting ...
Value is 7, waiting ...
Value is 8, waiting ...
Value is 9, waiting ...
Value is 10, waiting ...
Condition met. Value is now 11.
如果您不想手動實作回圈,而只是等到滿足條件,請使用wait_while:
use std::{
sync::{Arc, Condvar, Mutex},
thread::{sleep, JoinHandle},
time::Duration,
};
struct Counter {
value: Mutex<u32>,
condvar: Condvar,
}
fn start_counting_thread(counter: Arc<Counter>) -> JoinHandle<()> {
std::thread::spawn(move || loop {
sleep(Duration::from_millis(100));
let mut value = counter.value.lock().unwrap();
*value = 1;
counter.condvar.notify_all();
if *value > 15 {
break;
}
})
}
fn main() {
let counter = Arc::new(Counter {
value: Mutex::new(0),
condvar: Condvar::new(),
});
let counting_thread = start_counting_thread(counter.clone());
// Wait until the value more than 10
let mut value = counter.value.lock().unwrap();
value = counter.condvar.wait_while(value, |val| *val <= 10).unwrap();
println!("Condition met. Value is now {}.", *value);
// Unlock value
drop(value);
// Wait for counting thread to finish
counting_thread.join().unwrap();
}
Condition met. Value is now 11.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/488409.html
