SQLite多线程写锁文件解决方案

来源:互联网 发布:淘宝上买车险可靠吗 编辑:程序博客网 时间:2024/06/06 01:12

在sqlite编程中多线程同时写时会出现异常,我写了个类来解决这个问题。

思路很简单,就是在开始写操作时,记下写操作的托管线程id,表示目前有线程正在做写操作;其他线程来写时,需要先检测是否有进程正在做写操作,如果有就需要等待,等待到某一个配置的超时时间时,会抛出异常终止等待;如果没有则直接放行,此线程可以获得写锁。最后写操作执行完毕时需要释放锁。

下面是具体的代码:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. /// <summary>  
  2. /// 用于在多线程访问sqlite时防止同步写导致锁文件  
  3. ///   
  4. /// 使用方法:  
  5. /// using (SQLiteWriteLock sqliteLock = new SQLiteWriteLock(SQLite链接字符串))  
  6. /// {  
  7. ///     //sqlite 写操作代码  
  8. /// }  
  9. ///   
  10. /// 可以通过在配置文件appSettings节中添加设置 SQLiteWriteLockTimeout 的value值控制锁等待的超时时间,该值必须为正整数数字,单位为毫秒,  
  11. /// 默认的超时时间是1000ms  
  12. /// </summary>  
  13. public sealed class SQLiteWriteLock : IDisposable  
  14. {  
  15.     #region 静态字段和属性  
  16.     const short WAIT_TIME = 5;  
  17.     static readonly object locker = new object();  
  18.     static Dictionary<string, int> _dbThreadIdDict = new Dictionary<string, int>();  
  19.   
  20.     /// <summary>  
  21.     /// 获得写操作的超时时间,单位为毫秒,可以通过配置文件appSettings节中添加设置 SQLiteWriteLockTimeout 的value值控制锁等待的超时时间,该值必须为正整数数字,单位为毫秒  
  22.     /// 默认的超时时间是1000ms  
  23.     /// </summary>  
  24.     public static int SQLiteWriteLockTimeout  
  25.     {  
  26.         get  
  27.         {  
  28.             string configValule = ConfigurationManager.AppSettings["SQLiteWriteLockTimeout"];  
  29.             if (!string.IsNullOrEmpty(configValule))  
  30.             {  
  31.                 return int.Parse(configValule);  
  32.             }  
  33.             return 1000;  
  34.         }  
  35.     }  
  36.     #endregion  
  37.   
  38.     private readonly string _connString;  
  39.   
  40.     //隐藏无参构造函数  
  41.     private SQLiteWriteLock() { }  
  42.   
  43.     public SQLiteWriteLock(string connString)  
  44.     {  
  45.         _connString = connString;  
  46.         AcquireWriteLock();  
  47.     }  
  48.   
  49.     #region 私有方法  
  50.   
  51.     private void AcquireWriteLock()  
  52.     {  
  53.         int threadId = Thread.CurrentThread.ManagedThreadId;  
  54.   
  55.         int waitTimes = 0;  
  56.         while (_dbThreadIdDict.ContainsKey(_connString) && _dbThreadIdDict[_connString] != threadId)  
  57.         {  
  58.             Thread.Sleep(WAIT_TIME);  
  59.             waitTimes += WAIT_TIME;  
  60. #if DEBUG  
  61.             Console.WriteLine(_connString + " wait for " + waitTimes + " ms");  
  62. #endif  
  63.             if (waitTimes > SQLiteWriteLockTimeout)  
  64.             {  
  65.                 throw new TimeoutException("SQLite等待写操作超时");  
  66.             }  
  67.         }  
  68.   
  69.         lock (locker)  
  70.         {  
  71.             if (!_dbThreadIdDict.ContainsKey(_connString))  
  72.                 _dbThreadIdDict.Add(_connString, threadId);  
  73.         }  
  74.     }  
  75.   
  76.     private void ReleaseWriteLock()  
  77.     {  
  78.         lock (locker)  
  79.         {  
  80.             if (_dbThreadIdDict.ContainsKey(_connString))  
  81.             {  
  82.                 _dbThreadIdDict.Remove(_connString);  
  83.             }  
  84.         }  
  85.     }  
  86.   
  87.     #endregion  
  88.   
  89.     #region IDisposable 成员  
  90.   
  91.     public void Dispose()  
  92.     {  
  93.         ReleaseWriteLock();  
  94.     }  
  95.   
  96.     #endregion  
  97. }  

希望此文有用。