10 個のスレッドを生成し、各スレッドがデータベースを開き (すべてのスレッドに共通)、またはオープンに失敗した場合はデータベースを作成し ("Write-Ahead Log" オプションを使用)、データベースにテーブルを作成してから実行する単純なプログラムを作成しました。テーブルに一度に 1 つの行を追加する無限ループに入ります。プログラムが 5 分ごとに約 2 つのハンドルをリークすることがわかりました。Memory Verify というツールを試してみると、リークしたハンドルが SQLite3 ファイル ロックであることがわかりました (バージョン 3.7.13 の 34034 行)。 SQLiteまたは私がそれを使用する方法です。
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;
}
すべてのスレッドのハード ループは、INSERT ステートメントの準備、ステップ、およびファイナライズを行う ExecuteQuery を呼び出します。
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 の既知の問題ですか? 数日間グーグルで検索しようとしましたが、何も見つかりませんでした。
ご助力ありがとうございます。
よろしく、
アンドレア
PS WinXP 64 ビット PC でテストを実行していることを忘れていました。コンパイラは VS2010、アプリケーションは 32 ビットでコンパイルされ、SQLite バージョンは 3.7.13 です...