multithreading - 多线程场景中的 Microsoft.ACE.OLEDB.12.0 错误

标签 multithreading ms-access visual-c++ ms-office oledb

我在 x64 应用程序中使用了 Microsoft Access Database Engine 2010 (Microsoft Office 2016 的一部分)用于处理 mdb 文件。
但是,当前版本的 Microsoft Access Database Engine 2010(OLEDB 提供程序 Microsoft.ACE.OLEDB.12.0)有一个错误。
该引擎在多线程工作中崩溃。
如果我在不同的线程中与此提供程序创建两个 OLE DB(或 ADO DB)连接,那么其中一个将在 Mso40UIwin32client.dll 中崩溃。异常 0xC0000005: Access 冲突写入位置 0x0000000000000000。

异常堆栈:

  • 在 ACEOLEDBTest.exe 中的 0x00007FFB32361F28 处抛出异常:Microsoft
    C++ 异常:std::runtime_error 在内存位置
    0x0000006B771FEAF0。
  • 在 0x00007FFB32361F28 处抛出异常
    ACEOLEDBTest.exe:Microsoft C++ 异常:内存中的 [rethrow]
    位置 0x0000000000000000。
  • 在 0x00007FFB32361F28 处抛出异常
    在 ACEOLEDBTest.exe 中:Microsoft C++ 异常:std::runtime_error at
    内存位置 0x0000006B771FEAF0。
  • 抛出异常
    ACEOLEDBTest.exe 中的 0x00007FFB32361F28:Microsoft C++ 异常:
    内存位置 0x0000006B771FEFB8 处的 std::runtime_error。
  • 异常(exception)
    在 0x00007FFAF9ED1271 (Mso40UIwin32client.dll) 中抛出
    ACEOLEDBTest.exe:0xC0000005: Access 冲突写入位置
    0x0000000000000000。

  • 带有此错误的 C++ 代码示例:
    #include "stdafx.h"
    #include <atlcom.h>
    #include <atldbcli.h>
    #include <conio.h>
    
    typedef UINT(__stdcall* fnThread)(PVOID);
    
    HANDLE hExitEvent = NULL;
    
    UINT __stdcall DbThread1(IN PVOID context)
    {
        HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        _ASSERTE(SUCCEEDED(hRes));
    
        CDataSource DataSource;         // Data source connection object
    
        while (::WaitForSingleObject(hExitEvent, 0) != WAIT_OBJECT_0)
        {
            // Open DB connection
            ATLTRACE2(atlTraceGeneral, 0, L"DbThread1: Create connection...\n");
            hRes = DataSource.OpenFromInitializationString(L"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=\"C:\\Temp\\Index_empty1.mdb\"; Persist Security Info=False;");
            _ASSERTE(SUCCEEDED(hRes));
    
            // Close DB connection
            DataSource.Close();
            ATLTRACE2(atlTraceGeneral, 0, L"DbThread1: Close connection...\n");
            Sleep(20);
        }
    
        ::CoUninitialize();
        _endthreadex(0);
        return 0;
    }
    
    UINT __stdcall DbThread2(IN PVOID context)
    {
        HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        _ASSERTE(SUCCEEDED(hRes));
    
        CDataSource DataSource;         // Data source connection object
    
        while (::WaitForSingleObject(hExitEvent, 0) != WAIT_OBJECT_0)
        {
            // Open DB connection
            ATLTRACE2(atlTraceGeneral, 0, L"DbThread2: Create connection...\n");
            hRes = DataSource.OpenFromInitializationString(L"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=\"C:\\Temp\\Index_empty2.mdb\"; Persist Security Info=False;");
            _ASSERTE(SUCCEEDED(hRes));
    
            // Close DB connection
            DataSource.Close();
            ATLTRACE2(atlTraceGeneral, 0, L"DbThread2: Close connection...\n");
            Sleep(20);
        }
    
        ::CoUninitialize();
        _endthreadex(0);
        return 0;
    }
    
    int main()
    {
        ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
        hExitEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    
        const fnThread aPtrs[] = { DbThread1, DbThread2 };
        HANDLE hDbThread[_countof(aPtrs)] = { NULL };
        for (int nIndex = 0; nIndex < _countof(aPtrs); nIndex++) {
            if ((hDbThread[nIndex] = (HANDLE)::_beginthreadex(nullptr, 0, aPtrs[nIndex], nullptr, 0, nullptr)) == NULL)
            {
                return 1;
            }
        }
    
    
        CComVariant varData;
        printf("Press any key to exit...");
    
        // Loop until any key struck
        while (!_kbhit())
        {
            for (DWORD i = 0; i < 100; i++)
            {
                // Test for bug of the OLEDB provider for MS ACCESS 2010.
                varData.Clear();
            }
            Sleep(0);
        }
    
        // Request threads to exit
        SetEvent(hExitEvent);
    
        // Wait for threads to exit
        WaitForMultipleObjects(_countof(hDbThread), hDbThread, TRUE, INFINITE);
        for (auto& h : hDbThread) {
            CloseHandle(h);
        }
    
        CloseHandle(hExitEvent);
        ::CoUninitialize();
    
        return 0;
    }
    

    您应该使用 Visual C++ 2013/2015 为 x64 平台构建此示例。
    我在 MS forum 发现的类似错误.有谁能够帮助我?

    最佳答案

    我们在多线程 VB.Net (Framework v4.5.2) 服务应用程序中也遇到过这个问题。经过多次测试,我们发现解决此问题的唯一方法是使用单个线程或关闭连接池(使用 OLE DB Services=-2)。最后我们选择了后者,因为我们需要系统能够并行处理请求。

    仅供引用,我安装的 Office 2016 版本不包含此驱动程序(因此我们的程序通过了任何类型的基本测试),但它包含在我们客户安装的 Office 2016 版本中。到目前为止,我已经检查了“Microsoft Office Professional Plus 2016”(来自 MSDN 和 MS Partner Network)和“Microsoft Office 365 ProPlus”,但它们似乎都没有与 Microsoft.ACE.OLEDB.12.0 OLEDB 提供程序一起提供。此外,据我所知,唯一可供下载的 Microsoft Access Database Engine 2010 Redistributable 版本是 SP2(2013 年 7 月 22 日发布),因此很难在开发环境中对其进行测试!

    关于multithreading - 多线程场景中的 Microsoft.ACE.OLEDB.12.0 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37432816/

    相关文章:

    c++ - 如何从 C 调用 C++ 函数?

    multithreading - 在这种情况下如何设计线程同步

    Android - 从计时器线程更新位图

    python - 使用 Python 将文本文件导入 Access 2003 数据库

    vba - 达到 ComboBox 最大记录数

    c++ - 非常量引用的无效初始化

    multithreading - 如何将对堆栈变量的引用传递给线程?

    c++ - std::mutex 和 std::atomic 的链接问题

    ms-access - MS Access 如何从子表单获取另一个子表单的值?

    c++ - lambda 捕获变量的规则