2012-09-24 40 views
2

我編寫了一個簡單的程序,它產生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 ...

+0

考慮一下當所有線程啓動(幾乎是瞬時)所有調用打開失敗時會發生什麼,並且它們都嘗試創建一個新的數據庫。首先確保只有一個線程將被打開,從而一次創建一個數據庫。 – mtsvetkov

+0

嗨, 感謝您的回答。我創建了一個全局互斥鎖,我使用它來保護數據庫的打開/創建,但硬環路仍在泄漏句柄。 –

回答

0

檢查每個sqlite3_step之後是否有sqlite3_reset,因爲這是可能導致泄漏的一種情況。在使用sqlite3_prepare編寫語句並使用sqlite3_step執行語句之後,您需要始終使用sqlite3_reset重置它。