在sqlite編程中多線程同時寫時會出現(xiàn)異常,我寫了個類來解決這個問題。
思路很簡單,就是在開始寫操作時,記下寫操作的托管線程id,表示目前有線程正在做寫操作;其他線程來寫時,需要先檢測是否有進程正在做寫操作,如果有就需要等待,等待到某一個配置的超時時間時,會拋出異常終止等待;如果沒有則直接放行,此線程可以獲得寫鎖。最后寫操作執(zhí)行完畢時需要釋放鎖。
下面是具體的代碼:
SQLiteWriteLock
/// <summary>
/// 用于在多線程訪問sqlite時防止同步寫導致鎖文件
///
/// 使用方法:
/// using (SQLiteWriteLock sqliteLock = new SQLiteWriteLock(SQLite鏈接字符串))
/// {
/// //sqlite 寫操作代碼
/// }
///
/// 可以通過在配置文件appSettings節(jié)中添加設置 SQLiteWriteLockTimeout 的value值控制鎖等待的超時時間,該值必須為正整數(shù)數(shù)字,單位為毫秒,
/// 默認的超時時間是1000ms
/// </summary>
public sealed class SQLiteWriteLock : IDisposable
{
#region 靜態(tài)字段和屬性
const short WAIT_TIME = 5;
static readonly object locker = new object();
static Dictionary<string, int> _dbThreadIdDict = new Dictionary<string, int>();
/// <summary>
/// 獲得寫操作的超時時間,單位為毫秒,可以通過配置文件appSettings節(jié)中添加設置 SQLiteWriteLockTimeout 的value值控制鎖等待的超時時間,該值必須為正整數(shù)數(shù)字,單位為毫秒
/// 默認的超時時間是1000ms
/// </summary>
public static int SQLiteWriteLockTimeout
{
get
{
string configValule = ConfigurationManager.AppSettings["SQLiteWriteLockTimeout"];
if (!string.IsNullOrEmpty(configValule))
{
return int.Parse(configValule);
}
return 1000;
}
}
#endregion
private readonly string _connString;
//隱藏無參構(gòu)造函數(shù)
private SQLiteWriteLock() { }
public SQLiteWriteLock(string connString)
{
_connString = connString;
AcquireWriteLock();
}
#region 私有方法
private void AcquireWriteLock()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
int waitTimes = 0;
while (_dbThreadIdDict.ContainsKey(_connString) && _dbThreadIdDict[_connString] != threadId)
{
Thread.Sleep(WAIT_TIME);
waitTimes += WAIT_TIME;
#if DEBUG
Console.WriteLine(_connString + " wait for " + waitTimes + " ms");
#endif
if (waitTimes > SQLiteWriteLockTimeout)
{
throw new TimeoutException("SQLite等待寫操作超時");
}
}
lock (locker)
{
if (!_dbThreadIdDict.ContainsKey(_connString))
_dbThreadIdDict.Add(_connString, threadId);
}
}
private void ReleaseWriteLock()
{
lock (locker)
{
if (_dbThreadIdDict.ContainsKey(_connString))
{
_dbThreadIdDict.Remove(_connString);
}
}
}
#endregion
#region IDisposable 成員
public void Dispose()
{
ReleaseWriteLock();
}
#endregion
}
希望此文有用。