我们使用以下方法:
该应用程序在后台线程上与服务器同步数据。整个应用程序只共享一个SQLite连接对象。前台查询在后台同步运行的同时执行。所有这些都在Windows8.1版本的应用程序(即和类似软件)上工作得很好。然而,一旦我们切换到Xamarin/mono,我们就开始经常崩溃,如下所示。
本文的研究结果是:http://www.aaronheise.com/2012/12/monotouch-sqlite-sigsegv/
他使用的是Mono.Data.SqliteClient,而不是像我们一样的sqlite.net。
他的解决方案包括显式地释放命令对象,以确保GC能够跟上等等。当我试图将命令对象(从sqlite.net)包装在are (){}子句中时,我发现它们不是一次性的。
我尝试过插入100‘s的延迟,这样可以阻止崩溃,但是这对我们来说不是一个可行的解决方案。
这里有sqlite.net的希望吗,还是我应该找一种不同的方法来使用sqlite呢?
mono-rt: Stacktrace:
mono-rt: at <unknown> <0xffffffff>
mono-rt: at (wrapper managed-to-native) SQLite.SQLite3.Prepare2 (intptr,string,int,intptr&,intptr) <IL 0x0003c, 0xffffffff>
...
mono-rt:
Native stacktrace:
mono-rt:
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries
used by your application.发布于 2014-06-27 14:28:15
我非常肯定,当我尝试从多个线程中锤击同一个sqlite.net连接时,我得到的是有意义的错误,而不是SIGSEGV,但是如果您认为这是罪魁祸首,那么解决方案很简单:您需要限制对每次只访问一个线程的任何sqlite.net方法的访问。
在您共享应用程序中的单个SQLiteConnection实例的场景中(这是一种非常有效的处理方法),我建议创建一个简化的代理类包装您的sqlite.net连接,只公开您想要的方法,并保护对那些具有lock语句的方法的访问,即:
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();
}
}很明显,由于您是在多个线程上执行任务,所以您需要非常小心地避免引入争用条件,这就是为什么我包括了Upsert方法,该方法保证执行两步“更新或插入”操作。
发布于 2017-01-23 19:50:59
尝试将标志:SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex添加到SQLite连接构造函数中。解决了我们的问题。看起来SQLite在事务之后仍然做一些后台工作,使用内部互斥确保了基本的一致性。
https://stackoverflow.com/questions/24454045
复制相似问题