在 Windows C++ 代码中释放未持有的锁 CriticalSection

Getting Releasing unheld lock CriticalSection in Windows C++ code

我在下面的第二次尝试中收到警告“释放未持有的锁 'csCriticalSection'”。

这是我的代码,但没有所有 ADO 代码。我不知道为什么会收到此警告,因为如果 Execute() 函数失败,catch 将 运行 一个 LeaveCriticalSection 函数。如果 Execute() 函数成功,我调用 LeaveCriticalSection.

#include <windows.h>
#include <synchapi.h>
#include <comdef.h>
#include <conio.h>

CRITICAL_SECTION csCriticalSection;

_ConnectionPtr connectioncreate = nullptr;
_RecordsetPtr recordset = nullptr;

int main()
{
InitializeCriticalSectionAndSpinCount(&csCriticalSection, 4000);

// *** all ADO code here ***
//
// *** all ADO code here ***

BOOL bRanLeaveCriticalSection = FALSE;
try
    {
    EnterCriticalSection(&csCriticalSection);
    // Run an SQL command with ADO.
    /*
    connectioncreate->BeginTrans();
    connectioncreate->Execute(sSQL.data(), nullptr, adCmdText);
    connectioncreate->CommitTrans();
    */
    LeaveCriticalSection(&csCriticalSection);
    bRanLeaveCriticalSection = TRUE;
    }

catch (CONST _com_error& err)
    {
    connectioncreate->CommitTrans();
    if (bRanLeaveCriticalSection == FALSE)
        LeaveCriticalSection(&csCriticalSection);
    }


try
    {
    // From compiler at the next line "if (recordset)":
    // Warning  C26117  Releasing unheld lock 'csCriticalSection'
    if (recordset)
        if (recordset->State == adStateOpen)
            recordset->Close();
    }
catch (CONST _com_error& err)
    {
    err;
    }

_getch();
}

任何人都可以帮助我了解我收到此警告的原因以及如何修复它?

您没有在使用前初始化 csCriticalSection,例如:

...
CRITICAL_SECTION csCriticalSection;
...

int main()
{
    InitializeCriticalSection(&csCriticalSection); // <-- ADD THIS
    ...
    DeleteCriticalSection(&csCriticalSection); // <-- ADD THIS
}

而且,您真的根本不应该使用 bRanLeaveCriticalSection,这只是糟糕的代码设计。

您可以改用 __try/__finally 块(如果您的编译器支持的话),例如:

...
CRITICAL_SECTION csCriticalSection;
...

int main()
{
    ...

    try
        {
        EnterCriticalSection(&csCriticalSection);
        __try
            {
            // Run an SQL command with ADO.
            }
        __finally
            {
            LeaveCriticalSection(&csCriticalSection);
            }
        }
    catch (CONST _com_error& err)
        {
        ...
        }

    ...
}

然而,最好的选项是使用 RAII 包装器,让它为您调用 EnterCriticalSection()LeaveCriticalSection(),例如:

struct CRITICAL_SECTION_LOCK
{
    CRITICAL_SECTION &m_cs;

    CRITICAL_SECTION_LOCK(CRITICAL_SECTION &cs) : m_cs(cs) {
        EnterCriticalSection(&m_cs);
    }

    ~CRITICAL_SECTION_LOCK() {
        LeaveCriticalSection(&m_cs);
    }
};

...

CRITICAL_SECTION csCriticalSection;

int main()
{
    ...

    try
        {
        CRITICAL_SECTION_LOCK lock(csCriticalSection);
        // Run an SQL command with ADO.
        }
    catch (CONST _com_error& err)
        {
        ...
        }

    ...
}

或者更好,使用 C++ std::mutex instead, with a proper RAII lock such as std::lock_guard,例如:

#include <mutex>

std::mutex mtx;

...

int main()
{
    try
        {
        std::lock_guard<std::mutex> lock(mtx);
        // Run an SQL command with ADO.
        }
    catch (CONST _com_error& err)
        {
        ...
        }

    ...
}