多线程c++11-ish队列在windows上失败
Multithreaded c++11-ish queue fails on windows
我不太喜欢多线程,所以我很感谢你的建议。
在我的服务器这是写在生产者-消费者多线程风格queue
与其mutex
和cv
一起包裹:
template <typename Event>
struct EventsHandle {
public: // methods:
Event*
getEvent()
{
std::unique_lock<std::mutex> lock {mutex};
while (events.empty()) {
condition_variable.wait(lock);
}
return events.front();
};
void
setEvent(Event* event)
{
std::lock_guard<std::mutex> lock {mutex};
events.push(event);
condition_variable.notify_one();
};
void
pop()
{ events.pop(); };
private: // fields:
std::queue<Event*> events;
std::mutex mutex;
std::condition_variable condition_variable;
};
和它在消费者线程中的用法:
void
Server::listenEvents()
{
while (true) {
processEvent(events_handle.getEvent());
events_handle.pop();
}
};
和producer:
parse input, whatever else
...
setEvent(new Event {ERASE_CLIENT, getSocket(), nullptr});
...
void
Client::setEvent(Event* event)
{
if (event) {
events_handle->setEvent(event);
}
};
代码在linux上工作,我不知道为什么,但在windows MSVC13上失败。
在某些时候,会抛出以下对话框中的异常:"Unhandled exception at 0x59432564 (msvcp120d.dll) in Server.exe: 0xC0000005: Access violation reading location 0xCDCDCDE1".
调试显示在setEvent()
函数的std::lock_guard<std::mutex> lock(mutex)
行抛出异常。
我用谷歌搜索了一下这些文章:
http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
http://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables
所以…最后,在可爱的游戏名为"评论那行",原来,问题是在内存管理。事件的执行器导致失败。
作为结论,在来回传递对象时,最好像Jarod42提到的那样使用std::unique_ptr<>,或者像juanchopanza建议的那样使用值语义。
尽可能使用库,不要重新发明轮子=)
由于EventsHandle::pop
缺少互斥锁,导致数据竞争。
你的生产者线程可以通过调用setEvent()
将项目推到队列中,并在执行events.push(event)
时被抢占。现在一个消费者线程可以并发地执行events.pop()
。最终在queue
上出现了两次不同步的写操作,这是未定义的行为。
还要注意,如果您有多个消费者,则需要确保弹出的元素与之前从getEvent
检索的元素相同。以防一个消费者在两个呼叫之间被另一个消费者抢占。这是很难实现的两个独立的成员函数是同步的互斥锁是类的成员。这里通常的方法是提供一个单独的getEventAndPop()
函数,它在整个操作过程中保持锁,并摆脱当前拥有的单独函数。乍一看,这似乎是一个荒谬的限制,但多线程代码必须遵循不同的规则。
您可能还希望将setEvent
方法更改为在互斥锁仍然锁定时不通知。这取决于调度程序,但是等待通知的线程可能会立即唤醒,只是为了等待互斥锁。
void
setEvent(Event* event)
{
{
std::lock_guard<std::mutex> lock{mutex};
events.push(event);
}
condition_variable.notify_one();
};
我认为pop应该集成在getEvent()中。
这将防止更多的线程获得相同的事件(如果pop不在getEvent中,则更多的线程可以获得相同的事件)。
Event*
getEvent()
{
std::unique_lock<std::mutex> lock {mutex};
while (events.empty()) {
condition_variable.wait(lock);
}
Event* front = events.front();
events.pop();
return front;
};
- Active Directory:从网络服务帐户下运行的Windows服务调用ADsOpenObject时失败
- AWS AMI 中的 Windows DPAPI 失败,访问被拒绝
- 从 Linux OMI (omicli) 到 Windows WMI 的连接失败,并出现与 DMTF 相关的错误
- 在 Windows QDir::mkpath 和 QFile::rename 上报告成功,尽管失败了
- 在 Windows 上,stat 和 GetFileAttributes 对于包含奇怪字符的路径失败
- Mongodb C驱动程序在Windows上安装失败
- Windows 套接字和身份验证构建在包含 Poco-Library 时失败
- C++在Linux机器上使用cmake Qt5 Webkit进行交叉编译,使用mingw针对Windows,失败了
- 静态断言失败,出现"Windows headers require the default packing option..."
- GetModuleInformation 在 Windows 10 中的链接上失败
- 使用Outlook 2016:MAPISendMail在Windows应用程序中失败,并返回"MAPI_E_FAILURE"作为错误代码
- Visual Studio 2015 OpenCV Assertion 在 cv::imshow windows 中失败 (size.width>0 && size.height>0.cp
- opencv-wasm构建在windows上失败
- 在分配的结构中初始化 std::map 在 Windows 上失败
- 在Windows 7下可以从C#调用C DLL,但在Windows 10下失败
- C++/LapackE 代码在 Windows 上编译良好,但相同的代码在 Linux 上编译失败
- 在 Windows 7 的 CodeBlocks 16.01 中构建 glfw3 程序失败
- Ostream Tellp在Windows上失败,但在Linux上没有失败
- OpenCV导入在Windows容器中失败(在Windows Server 2016上)
- Rcpp Windows 编译失败