[英]Why does C++20 std::condition_variable not support std::stop_token?
[英]Is owning the lock required to request a stop while waiting on a condition_variable_any with stop_token?
在等待條件變量時,更改謂詞 state 的線程必須擁有鎖,因此在喚醒期間不會錯過更新。 根據文檔,這是必要的,即使在使用原子變量時也是如此。 但是我不確定request_stop()
是否已經正確處理了它。
那么問題來了,這兩個選項中哪一個是正確且符合標准的?
~jthread()
自然不會鎖定request_stop()
,但后來我不明白stop_token
和原子共享變量之間的區別在哪里。 因此,其中一個需要鎖,而另一個不需要。
#include <thread>
#include <condition_variable>
#include <iostream>
#include <chrono>
std::mutex m;
std::condition_variable_any cv;
void waitingThread(std::stop_token st){
std::unique_lock<std::mutex> lk(m);
std::cout<<"Waiting"<<std::endl;
cv.wait(lk, st, [](){return false;});
std::cout<<"Awake"<<std::endl;
}
void withoutLock(){
std::jthread jt{waitingThread};
std::this_thread::sleep_for(std::chrono::seconds(1));
jt.request_stop();
}
void withLock(){
std::jthread jt{waitingThread};
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lk(m);
jt.request_stop();
}
}
int main(){
withoutLock();
withLock();
}
即使共享變量是原子的,它也必須在擁有互斥量的同時被修改才能正確地將修改發布到等待線程。
std::condition_variable_any::wait 、 std::stop_token和std::stop_source不指定,如果等待中斷被保證注冊停止 state 中的變化。
在等待條件變量時,更改謂詞 state 的線程必須擁有鎖,因此在喚醒期間不會錯過更新。
...不指定,如果等待的中斷是保證注冊停止state的變化。
問題不完全是缺少更新,而是在notify
發生后和再次檢查謂詞之前回到睡眠狀態。
這個答案中的順序是有問題的。
根據文檔,這是必要的,即使在使用原子變量時也是如此。 但是我不確定
request_stop()
是否已經正確處理了它。
共享的 state 本身同步得很好: thread.stoptoken.intro/5說
調用函數
request_stop
、stop_requested
和stop_possible
不會引入數據競爭。 對返回 true 的request_stop
的調用與對返回true
的關聯stop_token
或stop_source
stop_requested
上的 stop_requested 的調用同步。
thread.condvarany.intwait中描述的等待謂詞循環也會有同樣的問題:
while (!stoken.stop_requested()) {
if (pred())
return true;
wait(lock);
}
return pred();
如果在第一行和wait(lock)
之間調用request_stop
,則stop_requested()
將變為true
並且在沒有人等待時通知條件變量。 然后我們將開始等待,等待永遠不會到來的通知。
如果request_stop
只能在wait
中釋放互斥量時調用,我們將始終保證在再次休眠之前檢查stop_requested()
。
事實上,GNU ISO C++ 庫為我們做了這件事: std::condition_variable_any
有一個額外的內部互斥鎖,用於將request_stop
回調(它只是通知請求線程中的 condvar)與等待謂詞循環正確同步。 因此,如果該行為是標准所要求的,那么您在這里就不需要自己的互斥鎖。
condition_variable_any::wait
和定時變體的所有stop_token
重載,注冊一個stop_callback
,它捕獲 Lockable object。然后在request_stop()
上執行回調,獲取鎖並通知等待線程,從而消除丟失的更新。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.