我編寫了一個簡單的程序,它產生10個線程,每個線程打開一個數據庫(對所有線程都通用),或者如果打開失敗,則創建一個數據庫(使用「Write-Ahead Log」選項) ,在數據庫上創建一個表,然後進入一個無限循環,在這個循環中,它在表中添加一行。我發現程序每隔5分鐘就會泄漏大約2個句柄,我嘗試了一種名爲Memory Verify的工具,它告訴我泄漏的句柄是SQLite3文件鎖(版本3.7.13上的34034行),但我不確定錯誤是在SQLite或我使用它的方式。C++ -SQLite3在多線程環境中泄漏句柄
我還沒有指定任何編譯器選項來構建SQLite3,因此它被構建爲多線程,並且據我瞭解,多線程應該在我的情況下正常工作,因爲每個線程都有自己的SQLite連接。
打開或創建我使用下面的代碼數據庫:
bool Create()
{
int iFlags = 0;
iFlags = iFlags | SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_CREATE;
return sqlite3_open_v2(dbName_sm.c_str(), &pHandle_m, iFlags, 0) == SQLITE_OK;
}
bool Open()
{
int iFlags = 0;
iFlags = iFlags | SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX;
return sqlite3_open_v2(dbName_sm.c_str(), &pHandle_m, iFlags, 0) == SQLITE_OK;
}
在每個線程的硬循環調用的executeQuery這確實準備,步驟和INSERT語句完成:
bool ExecuteQuery(const std::string& statement)
{
bool res = Prepare(statement);
if(!res)
{
return false;;
}
SQLiteStatus status = Step();
Finalize();
res = (ESuccess == status || EDatabaseDone == status);
return res;
}
bool Prepare(const std::string& statement)
{
return sqlite3_prepare_v2(pHandle_m, statement.c_str(), -1, &pStmt_m, 0) == SQLITE_OK;
}
enum SQLiteStatus { ESuccess, EDatabaseDone, EDatabaseTimeout, EDatabaseError };
SQLiteStatus Step()
{
int iRet = sqlite3_step(pStmt_m);
if (iRet == SQLITE_DONE)
{
return EDatabaseDone;
}
else if (iRet == SQLITE_BUSY)
{
return EDatabaseTimeout;
}
else if (iRet != SQLITE_ROW)
{
return EDatabaseError;
}
return ESuccess;
}
bool Finalize()
{
int iRet = sqlite3_finalize(pStmt_m);
pStmt_m = 0;
return iRet == SQLITE_OK;
}
你們是否在我的代碼中看到任何錯誤,或者它是SQLite中的已知問題?我試圖谷歌了幾天,但我找不到任何有關它。
非常感謝您的幫助。
問候,
安德烈
附:我忘了說我在一臺WinXP 64位個人電腦上運行我的測試,編譯器是VS2010,應用程序編譯爲32bit,SQLite版本爲3.7.13 ...
考慮一下當所有線程啓動(幾乎是瞬時)所有調用打開失敗時會發生什麼,並且它們都嘗試創建一個新的數據庫。首先確保只有一個線程將被打開,從而一次創建一個數據庫。 – mtsvetkov
嗨, 感謝您的回答。我創建了一個全局互斥鎖,我使用它來保護數據庫的打開/創建,但硬環路仍在泄漏句柄。 –