调用SQLite3.SetDirectory在Windows 8.1(WinRT)上发出System.AccessViolationException

时间:2015-05-05 15:03:08

标签: c# sqlite windows-8.1 sqlite-net

在我的Windows 8.1(WinRT)应用中,我使用SQLite v 3.8.9SQLite-net作为我的数据库,SemaphoreSlim作为我的同步执行器。它通常有效,但有时当我尝试删除表条目时它会在SQLite的C ++代码中崩溃。

  

(项目名称)(代码)的第一次机会异常:Microsoft C ++异常:内存位置(位置)的_com_error。

删除表格条目

private static SemaphoreSlim _mutex = new SemaphoreSlim(1,5);
public void DeleteItem(Item item)
{
    _mutex.Wait();
    using (var connection = new SQLiteConnection(Path))
    {
         connection.Delete(item);
    }
    _mutex.Release();
}

SQLite.cs

public SQLiteConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
{
    ...
#if NETFX_CORE
        SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path);
#endif
    ...
}

在调用SQLite3.SetDirectory时发生崩溃。

例外:

  

System.AccessViolationException

消息:

  

尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

堆栈跟踪:

  

在SQLite.SQLite3.SetDirectory(UInt32 directoryType,String directoryPath)

     

在SQLite.SQLiteConnection..ctor(String databasePath,SQLiteOpenFlags openFlags,Boolean storeDateTimeAsTicks)

     

在SQLite.SQLiteConnection..ctor(String databasePath,Boolean storeDateTimeAsTicks)

问题

我猜这必定是一个线程问题因为它通常有效并且有不规则的崩溃;但是我找不到任何东西。

异常的原因是什么,我该怎么做才能解决?

我不认为它是损坏的内存,可能受到保护,但我相当确定只有一个线程正在访问它

1 个答案:

答案 0 :(得分:1)

最后,尽管我确信一次只有一个线程正在访问SQLite数据库,但事实证明我有一些我没想到同时被调用的次要代码;这导致了AccessViolationException

为了确保将来不会出现此问题,我执行了以下操作:

  • 将整个SQLite代码移动到另一个项目以试图隔离它。
  • 在项目中实现了半工厂模式,以确保只有一个线程使用它(这也使代码看起来更好)

工厂数据库类

public class DataBaseConnection: SQLite.SQLiteConnection
{
   private const string _path = "MySQlitePath";
   private static SemaphoreSlim _contextMutex = new SemaphoreSlim(1, 5);
   private DataBaseConnection() : base(_path)
   {
   }

   public static DataBaseConnection CreateDataBaseConnection()
   {
       _contextMutex.Wait();
       return new DataBaseConnection();
   }

   private bool disposed = false;
   protected override void Dispose(bool disposing)
   {
       if (disposed)
          return;
       if(disposing)
       {

       }
       disposed = true;
       base.Dispose(disposing);
       _contextMutex.Release();
    }
}

使用工厂

using (var connection = DataBaseConnection.CreateDataBaseConnection())
{
     connection.Delete(item);
}

自从使用此功能后,我再也没见过AccessViolationException

使用多个数据库连接

如果您使用多个连接(即不同的数据库路径),例如:

  • MySQlitePath_1
  • MySQlitePath_2
  • ...
  • MySQlitePath_N

您应该始终使用相同的同步机制(在我的情况下为SemaphoreSlim),以确保在任何给定时间只打开一个 SQLite连接;即使他们正在访问不同的文件。