如何安全地删除 ATL DLL 中的 std::thread

Posted

技术标签:

【中文标题】如何安全地删除 ATL DLL 中的 std::thread【英文标题】:How to safely remove std::thread in ATL DLL 【发布时间】:2017-04-06 18:22:33 【问题描述】:

我写了一个 ATL DLL,但我遇到了 std::thread 的问题,我曾经运行 asyn 方法。我实现了异步执行操作的方法。当客户端尝试删除已完成线程的对象类时,就会出现此问题。

这是我的代码:

STDMETHODIMP CQRCodeGenerator::GenerateAsync(QRCodeTypeEnum QRCodeType, QRCodeFormatEnum QRCodeFormat, LONG QRCodePx, BSTR ImageFile)


if (ImageFile == nullptr) ImageFile = L"";

//stack to log file
OPFHelper::add_execute_method(this, L"CQRCodeGenerator::GenerateAsync",
    std::vector<std::wstring>OPFHelper::ConvertToWSting((LONG)QRCodeType),
    OPFHelper::ConvertToWSting((LONG)QRCodeFormat), OPFHelper::ConvertToWSting((LONG)QRCodePx), ImageFile);

t = std::thread(&CQRCodeGenerator::run, this, QRCodeType, QRCodeFormat, QRCodePx, ImageFile);
return S_OK;


void CQRCodeGenerator::run(enum QRCodeTypeEnum QRCodeType, enum QRCodeFormatEnum QRCodeFormat, LONG QRCodePx, BSTR ImageFile)


 ......

Fire_OnGenerate(this,ImageFile, _pQRCode, _pInvoiceID, _pQRCodeMD5, _pKS,nullptr);
   
    std::thread.h 文件中声明 当我收到事件并尝试删除 obj QRCodeGenerator 时出现错误。

我知道这是内存线程移除的问题,因为我执行了同步函数Generate,没有报错。

但我不知道如何删除这个线程并检测Client 何时想要删除 obj。第二件事它无法理解为什么当线程助手不再工作时释放内存会出现问题。

【问题讨论】:

你可以在 QRCodeGenerator 的析构函数中做点什么吧? @TonyJ 对,但是 whitch 怎么办?客户端销毁 obj 时调用哪个方法? HRESULT FinalConstruct() / void FinalRelease() ?什么? t.join() ? 我不熟悉FinalConstruct()/FinalRelease(),但是如果你写一个函数来调用t.join()如果线程没有完成,那么你可以从FinalConstruct()调用它/FinalRelease() 和析构函数。或者,您可以将 CQRCodeGenerator 重构为只是一个包装类,因此线程不会与其耦合。 @TonyJ 感谢您的建议! 【参考方案1】:

在销毁线程之前你会调用std::thread::join()detach() 吗?否则std::thread 析构函数应该触发terminate() 并中止程序。

如果某物拥有线程(如“客户端试图删除线程已经完成的对象类”),例如,该对象可能在其析构函数中调用t.join()

还请注意,您不应该破坏 Fire_OnGenerate 内的对象 - 这是在运行线程范围内调用的。所以你基本上会破坏一个仍在运行的线程(它只能在Fire_OnGenerate返回后完成)。

【讨论】:

我说的是事件会返回 OnGenerate 的情况。那么我必须在 ATL 类中添加 t.join() 吗? HRESULT 最终构造()?无效的最终版本?我不知道客户端尝试销毁 obj 时调用了 whitch 方法。

以上是关于如何安全地删除 ATL DLL 中的 std::thread的主要内容,如果未能解决你的问题,请参考以下文章

ATL COM dll 中的缓冲区溢出

在构建导出包含ATL :: CString成员的类的DLL时发出警告C4251

atl.dll已加载,但对dllregisterserver的调用失败,错误代码0x8002801c怎么办

WTL强制资源从非mfc应用程序中的dll加载的方式? (我们使用的是 WTL/ATL,不是直接的 win32)

使用 ATL 编译 dll,将方法参数作为接口,但将它们作为 coclasses

如何在基于 ATL 的服务器中正确转换和使用本机 COM 类型?