問(wèn)題描述
我正在處理的一個(gè)項(xiàng)目使用多個(gè)線程來(lái)處理一組文件.每個(gè)線程都可以將文件添加到要處理的文件列表中,所以我把(我認(rèn)為是)一個(gè)線程安全隊(duì)列放在一起.相關(guān)部分如下:
A project I'm working on uses multiple threads to do work on a collection of files. Each thread can add files to the list of files to be processed, so I put together (what I thought was) a thread-safe queue. Relevant portions follow:
// qMutex is a std::mutex intended to guard the queue
// populatedNotifier is a std::condition_variable intended to
// notify waiting threads of a new item in the queue
void FileQueue::enqueue(std::string&& filename)
{
std::lock_guard<std::mutex> lock(qMutex);
q.push(std::move(filename));
// Notify anyone waiting for additional files that more have arrived
populatedNotifier.notify_one();
}
std::string FileQueue::dequeue(const std::chrono::milliseconds& timeout)
{
std::unique_lock<std::mutex> lock(qMutex);
if (q.empty()) {
if (populatedNotifier.wait_for(lock, timeout) == std::cv_status::no_timeout) {
std::string ret = q.front();
q.pop();
return ret;
}
else {
return std::string();
}
}
else {
std::string ret = q.front();
q.pop();
return ret;
}
}
但是,我偶爾會(huì)在 if (...wait_for(lock, ti??meout) == std::cv_status::no_timeout) { }
塊中出現(xiàn)段錯(cuò)誤,并且在 gdb 中檢查表明由于隊(duì)列為空,出現(xiàn)段錯(cuò)誤.這怎么可能?我的理解是 wait_for
只在收到通知時(shí)返回 cv_status::no_timeout
,并且這應(yīng)該只在 FileQueue::enqueue
之后發(fā)生剛剛將一個(gè)新項(xiàng)目推送到隊(duì)列中.
However, I am occasionally segfaulting inside the if (...wait_for(lock, timeout) == std::cv_status::no_timeout) { }
block, and inspection in gdb indicates that the segfaults are occurring because the queue is empty. How is this possible? It was my understanding that wait_for
only returns cv_status::no_timeout
when it has been notified, and this should only happen after FileQueue::enqueue
has just pushed a new item to the queue.
推薦答案
根據(jù)標(biāo)準(zhǔn) condition_variables
允許虛假喚醒,即使事件沒(méi)有發(fā)生.在虛假喚醒的情況下,它會(huì)返回 cv_status::no_timeout
(因?yàn)樗鼏拘讯皇浅瑫r(shí)),即使它沒(méi)有被通知.正確的解決方案當(dāng)然是在繼續(xù)之前檢查喚醒是否真的合法.
According to the standard condition_variables
are allowed to wakeup spuriously, even if the event hasn't occured. In case of a spurious wakeup it will return cv_status::no_timeout
(since it woke up instead of timing out), even though it hasn't been notified. The correct solution for this is of course to check if the wakeup was actually legit before proceding.
細(xì)節(jié)在標(biāo)準(zhǔn) §30.5.1 [thread.condition.condvar] 中指定:
The details are specified in the standard §30.5.1 [thread.condition.condvar]:
——當(dāng)通過(guò)調(diào)用 notify_one()、調(diào)用 notify_all()、abs_time 指定的絕對(duì)超時(shí) (30.2.4) 或虛假發(fā)出信號(hào)時(shí),函數(shù)將解除阻塞.
—The function will unblock when signaled by a call to notify_one(), a call to notify_all(), expiration of the absolute timeout (30.2.4) speci?ed by abs_time, or spuriously.
...
返回: cv_status::timeout 如果 abs_time 指定的絕對(duì)超時(shí) (30.2.4) 過(guò)期,則為 cv_status::no_timeout.
Returns: cv_status::timeout if the absolute timeout (30.2.4) speci?edby abs_time expired, other-ise cv_status::no_timeout.
這篇關(guān)于C++11 線程安全隊(duì)列的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!