c# - 具有多线程访问的SQLitePCLRaw.provider.e_sqlite3.dll中的System.AccessViolationException或System.ExecutionEngineException崩溃

标签 c# multithreading sqlite xamarin.forms entity-framework-core

编辑:(由数字6解决)

当多个线程同时访问我的System.AccessViolationException时,是什么导致SQLitePCLRaw.provider.e_sqlite3.dll中的System.ExecutionEngineExceptionFooDbContext崩溃?

我有一个使用NETstandard 2.0.3,Microsoft.EntityFrameworkCore 2.2.4,Microsoft.EntityFrameworkCore.Sqlite 2.2.4支持UWP,Android和iOS的Xamarin Forms应用程序(3.5.0.169047),并且我遇到了可重现的崩溃情况(它确实发生在UWP上)我无法解决同时从两个不同线程同时访问设备上的sqlite数据库期间出现的问题。我有一个同步过程(将本地数据推送到API并从API提取在线数据)可能需要一分钟左右的时间,因此我需要在单独的线程中执行以使UI在其操作期间保持响应。我还需要允许在同步期间查询本地数据,以允许在同步期间进行导航或在同步期间在应用程序内进行其他只读数据操作。如果我在同步过程中未执行任何数据访问操作,则长时间运行的同步工作会很好,但是在完成任何中断的较短数据访问操作后立即崩溃。

从Visual Studio 2017(v15.9.5)的Debug输出中可以看出,以下是我所见的两个崩溃异常(可能与定时相关,导致相同的复制崩溃)。

  • 在SQLitePCLRaw.provider.e_sqlite3.dll中发生了类型为'System.AccessViolationException'的未处理的异常
    尝试读取或写入 protected 内存。这通常表明其他内存已损坏。
  • SQLitePCLRaw.provider.e_sqlite3.dll
  • 中发生类型为'System.ExecutionEngineException'的未处理异常

    调试时,没有有关该异常的其他详细信息;它发生在同步代码的不同长时间运行的行中,具体取决于执行中断操作的时间;调试器显示发生异常的长时间运行代码都包含在Try { ... } Catch(Exception) { ... }尝试在我的代码中进行阻止。

    可能是什么原因造成的,我该如何解决?

    我已经经历了以下所有方面:
  • SQLite用法是否与多个线程兼容?
  • 是;根据https://www.sqlite.org/threadsafe.html的默认设置,它处于“序列化”模式,并且支持多线程使用而没有限制。正在使用的SQLite的基础版本是3.26.0,该版本是我在调试时调查Microsoft.Data.Sqlite.SQLiteConnection信息时确定的。
  • 是因为我不能同时打开多个具有写功能的连接吗?
  • 否;我什至使用Microsoft.Data.Sqlite.SqliteConnectionStringBuilder修改了我的连接字符串,以根据每个数据访问的需要使用适当的Mode(SqliteOpenMode.ReadOnlySqliteOpenMode.ReadWriteCreate)。
  • 是因为中断线程的FooDbContextDispose()摆脱了长时间运行的线程的FooDbContext所依赖的资源吗?
  • 否;我做了很多调查,因为那是崩溃之前我可能遇到的最后一个断点。即使当我覆盖Dispose中的FooDbContext方法不执行任何操作,甚至不调用基类的Dispose(不建议使用,但我暂时尝试过)时,崩溃仍然发生。
  • 是否可以使用Microsoft.Data.Sqlite.SqliteConnectionStringBuilderMicrosoft.Data.Sqlite.SQLiteConnectionMicrosoft.EntityFrameworkCore.DbContextOptionsBuilderUseSqlite函数设置一项设置,以确保使用了序列化模式(我目前还不能100%地确定使用了该模式)?
  • 否;我进行了广泛研究,该选项必须隐藏在所选SQLite库的内部。
  • 我进行了大量的阅读和研究,但仍然没有其他可以尝试的地方。
  • https://www.sqlite.org/sharedcache.html
  • https://www.sqlite.org/lockingv3.html
  • https://www.sqlite.org/atomiccommit.html#sect_9_0
  • https://www.sqlite.org/uri.html
  • https://docs.microsoft.com/en-us/ef/core/get-started/uwp/getting-started
  • https://docs.microsoft.com/en-us/ef/core/get-started/netcore/new-db-sqlite
  • https://github.com/aspnet/EntityFrameworkCore/issues/5466
  • https://docs.microsoft.com/en-us/windows/uwp/data-access/sqlite-databases
  • https://www.connectionstrings.com/sqlite/
  • https://csharp.hotexamples.com/examples/-/DbContextOptionsBuilder/UseSqlite/php-dbcontextoptionsbuilder-usesqlite-method-examples.html
  • https://system.data.sqlite.org/index.html/info/dd30ecb89d423c4c
  • https://www.sqlite.org/src/info/e8d439c77685eca6
  • https://forums.asp.net/t/2143077.aspx?EntityFramework+Core+Do+we+have+to+explicitly+dispose+the+DBContext
  • https://github.com/aspnet/EntityFrameworkCore/issues/9901
  • https://xamarinhelp.com/entity-framework-core-xamarin-forms/

  • 编辑:为我解决了这个问题的答案:
  • 我注意到异常来自的dll是SQLitePCLRaw.provider.e_sqlite3.dll。这导致我查看了实际上是如何设置低级SQLite库的,最终是对SQLitePCL.Batteries_V2.Init();的调用选择了要使用的特定于平台的低级SQLite提供程序。这可能是错误的吗?
  • 是;事实证明,在阅读https://github.com/ericsink/SQLitePCL.raw/wiki/SQLitePCL.Batteries.Init#what-does-batteries_v2init-do上的Wiki信息后,对SQLitePCL.Batteries_V2.Init的调用仅打算在每个平台上进行一次(在平台特定的代码中,或者在共享代码中,只要在共享项目中还安装了Microsoft.EntityFrameworkCore.Sqlite,作为每个平台的特定项目)。我的SQLitePCL.Batteries.Init用法错误地在OnConfiguringFooDbContext内部,这使得它在每次配置FooDbContext时调用一次,而不是在每次应用程序启动时调用一次。 SQLitePCL.Batteries_V2.Init();行从OnConfiguring中移出,并移到我的共享项目中的App.xaml.cs构造函数中,对此进行了修复!在中断线程的数据访问之后,不再发生崩溃。 我真的希望这可以为某人节省大量的麻烦,而这又使我避免陷入困境。
  • 最佳答案

    为我解决了这个问题的答案:

  • 我注意到异常来自的dll是SQLitePCLRaw.provider.e_sqlite3.dll。这导致我查看了实际上是如何设置低级SQLite库的,最终是对SQLitePCL.Batteries_V2.Init();的调用选择了要使用的特定于平台的低级SQLite提供程序。这可能是错误的吗?
  • 是;事实证明,在阅读https://github.com/ericsink/SQLitePCL.raw/wiki/SQLitePCL.Batteries.Init#what-does-batteries_v2init-do上的Wiki信息后,对SQLitePCL.Batteries_V2.Init的调用仅打算在每个平台上进行一次(在平台特定的代码中,或者在共享代码中,只要在共享项目中还安装了Microsoft.EntityFrameworkCore.Sqlite,作为每个平台的特定项目)。我的SQLitePCL.Batteries.Init用法错误地在OnConfiguringFooDbContext内部,这使得它在每次配置FooDbContext时调用一次,而不是在每次应用程序启动时调用一次。 SQLitePCL.Batteries_V2.Init();行从OnConfiguring中移出,并移到我的共享项目中的App.xaml.cs构造函数中,对此进行了修复!在中断线程的数据访问之后,不再发生崩溃。 我真的希望这可以为某人节省大量的麻烦,而这又使我避免陷入困境。
  • 关于c# - 具有多线程访问的SQLitePCLRaw.provider.e_sqlite3.dll中的System.AccessViolationException或System.ExecutionEngineException崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55767533/

    相关文章:

    C# float 转十进制

    c# - 如何将图像保存到 Azure Blob 并使用特定字段命名并返回 Blob Url 并将其保存到 .net core 2.2 中的数据库

    java - 在java中将MySQL数据库转换为SQLite单个文件

    android - 在Android SQLITE中删除多行

    Python - 如何将 SQLAlchemy 连接到内存中的现有数据库

    c# - 调用简单的 AJAX WebMethod 总是会导致 "fail"回调

    c# - 将逻辑调用上下文从 OWIN 管道传递到 WebApi Controller

    c# - c#中的嵌套锁定误解?

    c++ - 使用线程时测量执行时间

    java - 如果一个程序完全由线程安全类组成,那么它是线程安全程序吗?