首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sqlite.net +单调= SIGSEGV崩溃

sqlite.net +单调= SIGSEGV崩溃
EN

Stack Overflow用户
提问于 2014-06-27 14:16:18
回答 2查看 1.8K关注 0票数 5

我们使用以下方法:

  • Xamarin 3 (Xamarin形式)
  • MonoTouch
  • sqlite.net
  • iOS模拟器/硬件

该应用程序在后台线程上与服务器同步数据。整个应用程序只共享一个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呢?

代码语言:javascript
复制
    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.
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-06-27 14:28:15

我非常肯定,当我尝试从多个线程中锤击同一个sqlite.net连接时,我得到的是有意义的错误,而不是SIGSEGV,但是如果您认为这是罪魁祸首,那么解决方案很简单:您需要限制对每次只访问一个线程的任何sqlite.net方法的访问。

在您共享应用程序中的单个SQLiteConnection实例的场景中(这是一种非常有效的处理方法),我建议创建一个简化的代理类包装您的sqlite.net连接,只公开您想要的方法,并保护对那些具有lock语句的方法的访问,即:

代码语言:javascript
复制
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方法,该方法保证执行两步“更新或插入”操作。

票数 4
EN

Stack Overflow用户

发布于 2017-01-23 19:50:59

尝试将标志:SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex添加到SQLite连接构造函数中。解决了我们的问题。看起来SQLite在事务之后仍然做一些后台工作,使用内部互斥确保了基本的一致性。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24454045

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档