multithreading - 具有不同文件的多个线程之间的 Sqlite 死锁

标签 multithreading macos sqlite deadlock

我有一个 OS X 应用程序(Yosemite,10.10),它执行长时间运行的作业,涉及跨多个线程大量使用 sqlite。我在 8 个线程中遇到了死锁,所有线程都陷入连接到不同数据库文件的 sqlite 代码中。它们之间不存在明显的资源相关联系。我正在新的 Mac Pro(2013 年末)上调试它。

其中有四个人在这个堆栈中。其中,三个在同一个表上操作(同样,不同的数据库文件);三个正在更新,一个正在查询。

__psynch_mutexwait
_pthread_mutex_lock
unixLock
sqlite3PagerSharedLock
sqlite3BtreeBeginTrans
sqlite3VdbeExec
sqlite3_step

其中一个位于此堆栈中,更新与上面堆栈中的三个表相同的表。

guarded_close_np
nolockClose
pager_end_transaction
sqlite3BtreeCommitPhaseTwo
sqlite3VdbeHalt
sqlite3VdbeExec
sqlite3_step

此堆栈中有两个文件,在不同位置打开同名的数据库文件。打开模式为SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX .

__psynch_mutexwait
_pthread_mutex_lock
sqlite3ParseUri
openDatabase

一个在这个堆栈上,结束一个事务。

__psynch_mutexwait
_pthread_mutex_lock
unixLock
sqlite3VdbeHalt
sqlite3VdbeExec
sqlite3_step

那么,问题是:什么会导致 sqlite 在不涉及任何共享资源的情况下死锁?

更新:我现在有七个线程锁定调用 sqlite3_open_v2和一个 sqlite3_close ,全部位于不同的数据库文件中(多个具有相同的名称,但位于不同的文件夹中)。堆栈是:

__psynch_mutexwait
_pthread_mutex_lock
sqlite3ParseUri
openDatabase

关闭堆栈是:

guarded_close_np
unixClose
sqlite3PagerClose
sqlite3BtreeClose
sqlite3LeaveMutexAndCloseZombie
sqlite3Close

通过修复一些内存泄漏(这不是使用 ARC 运行)并删除一些事务语句,我能够让它在锁定之前运行更长时间。

更新 2: 我已连接 SQLITE_LOG通过sqlite3_config ( documentation ),并且我看到大量代码 28 ( sqlite_warning ) 的日志记录,并带有消息“文件在打开时重命名:”。

更新 3: 我删除了机器并重新安装了 Yosemite,试图排除文件系统问题。我仍然以同样的方式锁定。它会运行几分钟,然后线程一个接一个地锁定。 guarded_close_np 有一个,陷入汇编指令jae <address here>跳转到的地址有指令 retq 。我问过separate question关于文件被重命名的 sqlite 日志消息,希望与其相关。

最佳答案

听起来您陷入了 UNIX 主互斥体的困境,需要在文件关闭之前获取该互斥体:

/*
** Close a file.
*/
static int unixClose(sqlite3_file *id){  
  int rc = SQLITE_OK;
  unixFile *pFile = (unixFile *)id;
  verifyDbFile(pFile);
  unixUnlock(id, NO_LOCK);
  unixEnterMutex(); <- HERE
...

此互斥锁主要在低级文件操作期间保留。您必须找到保存互斥锁的线程并查看它在做什么。也许它在缓慢或损坏的文件系统上运行。

关于multithreading - 具有不同文件的多个线程之间的 Sqlite 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27784704/

相关文章:

python - 连接到 Flask 中的数据库,哪种方法更好?

c++ - 并发访问 Map C++ 中的不同键

php - PHP pthreads如果至少有1个线程完成了该工作,则停止所有线程

python - 在Python中的类中处理socket进程

macos - 获取 SKSpriteNode 纹理在该位置的 alpha 值

macos -/usr/local/bin 和/usr/local/share 的权限问题

java - 我如何在java中删除球、改变颜色和改变球的类型

macos - 我可以删除自定义 NSMenu 的顶部和底部填充吗?

ios - 将表添加到现有数据库 IOS sqlite

SQLite 插入值并选择