【发布时间】:2018-11-23 13:47:44
【问题描述】:
仍在试图弄清楚 ADODB 的连接发生了什么以及为什么会发生某种崩溃。
问题是我们的代码中存在内存泄漏:
void getDetailConfig()
{
m_displayConf = new TestDetailDisplayCfg();
}
这个函数经常被调用,所以基本的内存泄漏。 用唯一的指针修复它
void getDetailConfig()
{
m_displayConf = std::make_unique<TestDetailDisplayCfg>();
}
是的,但是现在 ADODB 的 Recordset15::Close 内部开始发生访问违规。
inline HRESULT Recordset15::Close ( ) {
HRESULT _hr = raw_Close();
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}
LaneControl.exe 中 0x679E653F (msado15.dll) 处的未处理异常: 0xC000041D:在用户过程中遇到未处理的异常 回调。
所以以正确的方式调用所有析构函数导致了一个新问题,记录集在某处打开和关闭。
调试后发现 getDetailConfig 是从两个不同的线程调用的。
线程1
void updateIconStatus()
{
getDetailConfig();
}
线程 ID 5bA8
线程2
void CVTSDetailDisplay::setCurrentTestIconStatus(int status)
{
m_CurrentDialog->getDetailConfig();
}
线程 ID 6A4C
所以这 2 个线程调用 getDetailConfig,其中一个记录集被关闭,该记录集在另一个线程上打开,COM 对象被释放,什么不是。
这是您无法在另一个线程上关闭 ADO 记录集的问题吗?它更像是一种竞争条件吗? ADODB 级别出了什么问题?
【问题讨论】:
-
0xC000041D 实际上与 ADODB 没有太大关系。它可能发生在在 64 位版本的 Windows 上运行的 32 位应用程序中。在此之前有 another 异常被抛出到 Windows 消息处理程序(又名 WndProc,又名“用户回调”)中。这种异常很难正确处理,因为回调在 64 位窗口管理器中启动,并且无法通过这些层正确展开堆栈。专注于看到第一个事故,这就是它开始崩溃的地方。强制调试器在“第一次机会异常”时停止
-
Fwiw,ADODB 不是线程安全的。您必须编组接口指针,通常最容易做到this way。
-
我基本上认为该对象已被尝试释放两次(原因在我的回答中描述),又名“双重删除”,因此第二次发布确实失败了,因为该对象已经不再有效。事实上,ADODB 可能的非线程安全性(我不太了解)只会增加另一个伤害。