【发布时间】:2013-02-23 01:45:57
【问题描述】:
我正在处理的一个项目使用多个线程来处理一组文件。每个线程都可以将文件添加到要处理的文件列表中,因此我将(我认为是)一个线程安全队列放在一起。相关部分如下:
// 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;
}
}
但是,我偶尔会在 if (...wait_for(lock, timeout) == std::cv_status::no_timeout) { } 块内出现段错误,并且 gdb 中的检查表明正在发生段错误,因为队列为空。这怎么可能?据我了解,wait_for 仅在收到通知后才返回 cv_status::no_timeout,并且这仅应在 FileQueue::enqueue 刚刚将新项目推送到队列后发生。
【问题讨论】:
-
问题,你为什么要通过 ref-ref 获取
filename?我在这里看不到任何原因> -
@TonyTheLion 通常在 C++ 中,通过引用传递对象比制作副本更有效。在这种情况下,我还使用了移动语义,它允许编译器将字符串的内容移动到队列中,而不是制作另一个副本。
-
@slavik262:你在这里使用
std::forward是不正常的(在“通用引用”中使用),你应该只是std::move它。 -
实际上在这里利用移动语义的首选方法是使用
std::move并通过值而不是通过非常量右值引用来获取enqueue的filename参数。事实上,它只能用右值调用,这可能不是你想要的。
标签: c++ multithreading c++11 queue condition-variable