sqlite.net + monotouch = SIGSEGV crashes
I'm pretty sure I was getting meaningful errors instead of SIGSEGV's when I tried hammering the same sqlite.net connection from multiple threads, but if you believe that that's the culprit, the solution is simple: you need to restrict access to any sqlite.net methods which touch the database to one thread at a time.
In the scenario where you're sharing a single SQLiteConnection
instance in your app (which is a perfectly valid way of doing things), I recommend creating a simplified proxy class wrapping your sqlite.net connection, exposing only the methods that you want and protecting access to those with lock
statements, i.e:
public class DatabaseWrapper : IDisposable{ // Fields. private readonly SQLiteConnection Connection; private readonly object Lock = new object(); public DatabaseWrapper(string databasePath) { if (string.IsNullOrEmpty(databasePath)) throw new ArgumentException("Database path cannot be null or empty."); this.Connection = new SQLiteConnection(databasePath); } public IEnumerable<T> Entities<T>() where T : new() { lock (this.Lock) { return this.Connection.Table<T>(); } } public IEnumerable<T> Query<T>(string query, params object[] args) where T : new() { lock (this.Lock) { return this.Connection.Query<T>(query, args); } } public int ExecuteNonQuery(string sql, params object[] args) { lock (this.Lock) { return this.Connection.Execute(sql, args); } } public T ExecuteScalar<T>(string sql, params object[] args) { lock (this.Lock) { return this.Connection.ExecuteScalar<T>(sql, args); } } public void Insert<T>(T entity) { lock (this.Lock) { this.Connection.Insert(entity); } } public void Update<T>(T entity) { lock (this.Lock) { this.Connection.Update(entity); } } public void Upsert<T>(T entity) { lock (this.Lock) { var rowCount = this.Connection.Update(entity); if (rowCount == 0) { this.Connection.Insert(entity); } } } public void Delete<T>(T entity) { lock (this.Lock) { this.Connection.Delete(entity); } } public void Dispose() { this.Connection.Dispose(); }}
P.S. Obviously since you're doing things on multiple threads you need to be very careful not to introduce race conditions, which is why, for example, I included the Upsert
method that is guaranteed to perform the two-step "update or insert" operation atomically.
Try adding the flags: SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex
to your SQLite connection constructor. Solved our problem. Looks like SQLite still does some background work after transactions, using the internal mutex ensures the base consistency.