无用户代码的死锁 我在C++程序中使用了一个死锁,它使用了STD::线程,STD::互斥,STD::条件变量,等等。
这本身并没有什么奇怪的,直到我查看进程中每个线程的堆栈:无用户代码的死锁 我在C++程序中使用了一个死锁,它使用了STD::线程,STD::互斥,STD::条件变量,等等。,c++,multithreading,c++11,visual-studio-2013,deadlock,C++,Multithreading,C++11,Visual Studio 2013,Deadlock,这本身并没有什么奇怪的,直到我查看进程中每个线程的堆栈: 8532 0 Main Thread Main Thread msvcr120.dll!Concurrency::details::ExternalContextBase::Block Normal ntdll.dll!_ZwWaitForSingleObject@12() KernelBase.dll!_WaitForS
8532 0 Main Thread Main Thread msvcr120.dll!Concurrency::details::ExternalContextBase::Block Normal
ntdll.dll!_ZwWaitForSingleObject@12()
KernelBase.dll!_WaitForSingleObjectEx@12()
kernel32.dll!_WaitForSingleObjectExImplementation@12()
msvcr120.dll!Concurrency::details::ExternalContextBase::Block() Line 145
ntdll.dll!_ZwQueryVirtualMemory@24()
kernel32.dll!_BasepFillUEFInfo@8()
ntdll.dll!_ZwQueryInformationProcess@20()
msvcr120.dll!_initterm(void (void) * * pfbegin, void (void) * * pfend) Line 954
-
-
似乎没有线程在执行我的代码,我知道我们已经进入main,因为程序在挂起之前做了一些事情
我正在使用以下类与我的std::thread通信,以防我在那里犯了一些错误:
template <typename T>
class BlockingQueue
{
public:
BlockingQueue() : _active(true) {}
bool Get(T& out)
{
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [&](){ return !_queue.empty() || !_active; });
if (_queue.empty())
{
assert(!_active);
return false;
}
out = std::move(_queue.front());
_queue.pop();
return true;
}
void Put(const T& in)
{
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.push(in);
}
_cv.notify_one();
}
void Put(T&& in)
{
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.push(std::move(in));
}
_cv.notify_one();
}
void Finish()
{
{
std::unique_lock<std::mutex> lock(_mutex);
_active = false;
}
_cv.notify_all();
}
private:
bool _active;
std::mutex _mutex;
std::condition_variable _cv;
std::queue<T> _queue;
};
模板
类阻塞队列
{
公众:
BlockingQueue():_active(true){}
bool Get(T&out)
{
std::唯一的锁(互斥锁);
_cv.wait(lock,[&](){return!_queue.empty()| |!_active;});
if(_queue.empty())
{
断言(!\u活动);
返回false;
}
out=std::move(_queue.front());
_queue.pop();
返回true;
}
无效投入(常数T&in)
{
{
std::唯一的锁(互斥锁);
_排队。推(入);
}
_cv.通知_one();
}
无效投入(T&in)
{
{
std::唯一的锁(互斥锁);
_push(std::move(in));
}
_cv.通知_one();
}
空隙饰面()
{
{
std::唯一的锁(互斥锁);
_主动=假;
}
_cv.通知所有人();
}
私人:
布尔活跃;
std::mutex\u mutex;
std::条件变量cv;
std::queue\u queue;
};
我现在有两个想法:
[下面的帧可能丢失/不正确]
放入堆栈跟踪中,但如果不这样做,可能会发生这种情况事实证明,我未能替换队列中的项目,导致我的线程在从队列检索时死锁,这意味着调试器在欺骗我:(您应该在互斥锁内部通知,否则可能会遇到冲突:1.
\u cv.wait()
计算谓词;它返回false
2.notify\u all
称为3.在\u cv.wait()中调用wait(lock)
)
但不确定这是否是问题所在。我在看cppreference.com上std::condition_变量的文档,它似乎说在通知时不需要持有锁,事实上这样做是对性能的悲观(这是有意义的,因为任何因notify而唤醒的线程都会立即尝试获取锁并失败)“通知线程不需要将锁保持在与等待线程保持的锁相同的互斥体上;事实上,这样做是一种悲观的做法,因为通知线程会立即再次阻塞,等待通知线程释放锁。然而,一些实现(特别是pthreads的许多实现)认识到这种情况,并避免这种“匆忙等待”通过将等待线程从条件变量的队列直接传输到notify调用中的互斥体队列,而不唤醒它。“这就是他们所说的。在你的函数中放一些调试日志,看看它在哪里结束,这取决于情况。但是我检查了C++11的条件变量::wait
,它说在每次调用谓词之前都需要锁,所以它确实不能争用\u active
。
6296 0 Worker Thread msvcr120.dll!_threadstartex msvcr120.dll!Concurrency::details::ExternalContextBase::Block Normal
ntdll.dll!_ZwWaitForSingleObject@12()
KernelBase.dll!_WaitForSingleObjectEx@12()
kernel32.dll!_WaitForSingleObjectExImplementation@12()
msvcr120.dll!Concurrency::details::ExternalContextBase::Block() Line 145
msvcp120.dll!std::_Thrd_startX(struct _Thrd_imp_t *,unsigned int (*)(void *),void *)
msvcr120.dll!_callthreadstartex() Line 376
msvcr120.dll!_threadstartex(void * ptd) Line 354
kernel32.dll!@BaseThreadInitThunk@12()
ntdll.dll!___RtlUserThreadStart@8()
ntdll.dll!__RtlUserThreadStart@8()
template <typename T>
class BlockingQueue
{
public:
BlockingQueue() : _active(true) {}
bool Get(T& out)
{
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [&](){ return !_queue.empty() || !_active; });
if (_queue.empty())
{
assert(!_active);
return false;
}
out = std::move(_queue.front());
_queue.pop();
return true;
}
void Put(const T& in)
{
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.push(in);
}
_cv.notify_one();
}
void Put(T&& in)
{
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.push(std::move(in));
}
_cv.notify_one();
}
void Finish()
{
{
std::unique_lock<std::mutex> lock(_mutex);
_active = false;
}
_cv.notify_all();
}
private:
bool _active;
std::mutex _mutex;
std::condition_variable _cv;
std::queue<T> _queue;
};