【问题标题】:access violation inside ADODB recordset CloseADODB 记录集中的访问冲突关闭
【发布时间】: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 可能的非线程安全性(我不太了解)只会增加另一个伤害。

标签: c++ com ado


【解决方案1】:

我认为这是一个竞争条件。

如果之前已经调用了getDetailConfig() 函数,然后两个线程都调用了getDetailConfig(),这可能导致两个线程同时调用(之前存在的对象的)析构函数(std::unique_ptr 不是固有的线程安全的 AFAIK)。

然后,您需要确保交换指针的关键部分,例如将 std::mutex m_mutex; 添加为您的类的成员(理想情况下添加到成员列表中的第一位,因此它的有效期比 @987654325 长@member) 然后添加

void getDetailConfig()
{
    std::unique_lock<std::mutex> lock(m_mutex);
    m_displayConf = std::make_unique<TestDetailDisplayCfg>();
}

确保线程之间的交换被锁定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多