`sqlite3`忽略`sqlite3_busy_timeout`?

时间:2015-05-25 12:38:19

标签: c++ c sqlite

我在多线程应用程序中使用sqlite3(它使用SQLITE_THREADSAFE=2编译)。在观察窗口,我看到sqlite->busyTimeout == 600000,我。即应该有10分钟超时。但是,sqlite3_step以比10分钟后更快的速度返回SQLITE_BUSY(实际上会立即返回,就像我从未调用sqlite3_busy_timeout一样)。 sqlite3忽略超时并立即返回错误的原因是什么?

2 个答案:

答案 0 :(得分:6)

一种可能性:SQLite在检测到死锁时忽略超时。

方案如下。事务A以读者身份开始,后来尝试执行写入。交易B是一个作家(或者以这种方式开始,或者作为读者开始并首先提升为作家)。 B持有RESERVED锁定,等待读者清除,以便开始编写。 A持有SHARED锁定(它是读者)并尝试获取RESERVED锁定(因此它可以开始写入)。有关各种锁类型的说明,请参阅http://sqlite.org/lockingv3.html

在这种情况下取​​得进展的唯一方法是回滚其中一个事务。没有多少等待会有所帮助,因此当SQLite检测到这种情况时,它不会遵循忙碌超时。

有两种方法可以避免死锁:

  1. 切换到WAL mode - 它允许一位作家与多位读者共存。
  2. 使用BEGIN IMMEDIATE启动最终可能需要编写的事务 - 这样,它就会立即以编写者身份启动。这当然会降低系统中的潜在并发性,作为避免死锁的代价。

答案 1 :(得分:-1)

我做了很多测试,并在这里与其他在多线程环境中使用SQLite的人分享。 SQLite线程支持没有详细记录,没有任何好的教程可以在一个地方描述所有线程问题。我制作了一个测试程序,创建了100个线程,并将随机查询(INSERTSELECTUPDATEDELETE)同时发送到单个数据库。我的回答是基于这个程序观察。

唯一真正的线程安全日志模式是WAL。它允许多个连接以与单线程应用程序相同的方式在一个进程内为同一数据库执行所需的任何操作。任何其他模式都不是独立于超时,繁忙处理程序和SQLITE_THREADSAFE预处理程序定义的线程安全。它们会定期生成SQLITE_BUSY,看起来像复杂的编程任务总是期望这样的错误并始终处理它。如果你需要线程安全的SQLite永远不会像signle线程一样返回SQLITE_BUSY,你必须设置WAL日志模式。

此外,您必须设置SQLITE_THREADSAFE=2SQLITE_THREADSAFE=1预处理器定义。

完成后,您必须从2个选项中进行选择:

  1. 您可以致电sqlite3_busy_timeout。这就足够了,你不需要打电话给sqlite3_busy_handler,即使是文件也不明显。它为您提供“默认”,“内置”超时功能。
  2. 您可以致电sqlite3_busy_handler并自行实施超时。我不明白为什么,但可能需要一些非标准的操作系统。当您调用sqlite3_busy_handler时,它会将超时重置为0(即禁用)。对于桌面Linux& Windows你不需要它,除非你想编写更复杂的代码。