sqlite.net + monotouch = SIGSEGV 崩溃 [英] sqlite.net + monotouch = SIGSEGV crashes

查看:93
本文介绍了sqlite.net + monotouch = SIGSEGV 崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用以下内容:

We're using the following:

  • Xamarin 3(Xamarin 表单)
  • 单点触控
  • sqlite.net
  • iOS 模拟器/硬件

应用在后台线程上与服务器同步数据.整个应用程序只共享一个 SQLite 连接对象.前台查询在后台同步运行的同时执行.所有这些都在应用程序的 Windows 8.1 版本上运行良好(即,在 MSFT Surface 和类似版本上).然而,一旦我们切换到 Xamarin/mono,我们就会开始不断崩溃,如下所示.

The app synchronizes data with a server on a background thread. There is only one SQLite connection object shared by the entire app. Foreground queries are executed at the same time the background sync is running. All of this has worked fine on a Windows 8.1 version of the app (i.e., on MSFT Surface and similar). However once we switched to Xamarin/mono we started getting constant crashes as shown below.

研究导致这篇文章:http://www.aaronheise.com/2012/12/monotouch-sqlite-sigsegv/

他使用的是 Mono.Data.SqliteClient,而不是我们现在使用的 sqlite.net.

He's using using Mono.Data.SqliteClient, not sqlite.net as we are.

他的解决方案涉及明确处置 Command 对象以确保 GC 可以跟上等.当我尝试将我的 Command 对象(来自 sqlite.net)包装在 using(){} 子句中时,我发现它们不是一次性的.

His solution involves explicitly disposing of Command objects in order to ensure the GC can keep up etc. When I tried to wrap my Command objects (from sqlite.net) in a using(){} clause I found out they are not disposable.

我试过插入 100 毫秒的延迟并阻止崩溃,但这对我们来说不是一个可行的解决方案.

I've tried inserting 100ms delays and that stops the crashes, however it's not a viable solution for us.

这里对 sqlite.net 有什么希望,还是我应该寻找一种不同的方式来使用 sqlite?

Is there any hope for sqlite.net here, or should I look for a different way to use 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.

推荐答案

当我尝试从多个线程敲击相同的 sqlite.net 连接时,我很确定我得到的是有意义的错误而不是 SIGSEGV,但如果你相信那是罪魁祸首,解决方案很简单:您需要将访问数据库的任何 sqlite.net 方法的访问权限限制为一次一个线程.

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.

在您在应用程序中共享单个 SQLiteConnection 实例的情况下(这是一种完全有效的做事方式),我建议创建一个简化的代理类来包装您的 sqlite.net 连接,只公开您想要的方法并保护对那些使用 lock 语句的访问,即:

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();
    }
}

附言显然,由于您在多个线程上做事,您需要非常小心,不要引入竞争条件,这就是为什么,例如,我包含了保证执行两步操作的 Upsert 方法原子地更新或插入"操作.

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.

这篇关于sqlite.net + monotouch = SIGSEGV 崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆