Reputation: 3129
In my Windows 8.1 (WinRT) app I am using SQLite v 3.8.9 with SQLite-net as my database, and SemaphoreSlim as my synchronization enforcer. It usually works, but sometimes it crashes in the SQLite's C++ code when I try to delete a table entry.
First-chance exception at (code) in (project name): Microsoft C++ exception: _com_error at memory location (location).
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();
}
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
...
}
The crash happens when SQLite3.SetDirectory
is called.
Exception:
Message:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Stacktrace:
at SQLite.SQLite3.SetDirectory(UInt32 directoryType, String directoryPath)
at SQLite.SQLiteConnection..ctor(String databasePath, SQLiteOpenFlags openFlags, Boolean storeDateTimeAsTicks)
at SQLite.SQLiteConnection..ctor(String databasePath, Boolean storeDateTimeAsTicks)
I am guessing that this must be a Threading issue because it usually works and has irregular crashes; but I am unable to find anything.
What can be the cause of the exception and what can I do to fix it?
I do not think it is corrupted memory, maybe protected, but I am fairly sure that only one of my threads are accessing it
Upvotes: 3
Views: 1138
Reputation: 3129
In the end, even though I was confident that only one thread was accessing the SQLite db at a time, it turned out that I had some minor code that I didn't expect was called at the same time; this caused the AccessViolationException
To ensure that this problem does not arise in the future, I did the following:
Factory Database class
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 the factory
using (var connection = DataBaseConnection.CreateDataBaseConnection())
{
connection.Delete(item);
}
Since using this, I've never seen the AccessViolationException
again.
If you are using Multiple Connections (i.e. different DB paths) such as:
You should use the same Synchronization Mechanism (in my case SemaphoreSlim
) throughout to ensure only one SQLite Connection is open at any given time; even though they are accessing different files.
Upvotes: 1