C++ 如何在多线程应用程序中使用SQLite?

C++ 如何在多线程应用程序中使用SQLite?,c++,multithreading,sqlite,C++,Multithreading,Sqlite,我正在开发一个以as作为数据库的应用程序,在理解如何在多线程中使用它时遇到了一些困难(不幸的是,其他堆栈溢出问题都没有真正帮助我) 我的用例:数据库有一个表,我们称之为“A”,它有不同的行组(基于它们的一列)。我有应用程序的“主线程”,它读取表A中的内容。此外,我决定偶尔更新一组行。为此,我希望生成一个新线程,删除组中的所有行,然后重新插入它们(这是在我的应用程序上下文中执行此操作的唯一方法)。这可能同时发生在不同的组上,因此我可能有2个以上的线程试图更新数据库 我使用来自每个线程的不同事务,即

我正在开发一个以as作为数据库的应用程序,在理解如何在多线程中使用它时遇到了一些困难(不幸的是,其他堆栈溢出问题都没有真正帮助我)

我的用例:数据库有一个表,我们称之为“A”,它有不同的行组(基于它们的一列)。我有应用程序的“主线程”,它读取表A中的内容。此外,我决定偶尔更新一组行。为此,我希望生成一个新线程,删除组中的所有行,然后重新插入它们(这是在我的应用程序上下文中执行此操作的唯一方法)。这可能同时发生在不同的组上,因此我可能有2个以上的线程试图更新数据库

我使用来自每个线程的不同事务,即在每个线程的更新周期开始时,我有一个开始。事实上,每个线程实际上所做的是调用“BEGIN”,从数据库中删除它需要“更新”的所有行,并用新值再次插入它们(在我的应用程序上下文中必须这样做)

现在,我正试图了解我是如何实现这一点的。我试着四处阅读(Stack Overflow,SQLite站点上的其他答案),但我没有找到所有答案。以下是我想知道的一些事情:

  • 我是否需要调用“open”并从每个线程创建一个新的sqlite结构
  • 我是否需要为所有这些添加任何特殊代码,或者它是否足以生成不同的线程、更新行,这样就可以了(因为我使用的是不同的事务)
  • 我看到了一些关于不同锁类型的讨论,以及调用某些API时可能会收到“SQLite busy”的消息,但老实说,我没有看到任何参考资料能够完全解释我需要考虑的所有这些。我需要吗
  • 如果有人能回答这些问题/为我指出一个好资源的方向,我将非常感激

    更新1:根据我到目前为止阅读的所有内容,似乎不可能有两个线程将写入数据库文件

    请参阅:。在第3.0节中:保留锁意味着进程计划在将来某个时候写入数据库文件,但它当前只是从文件中读取。一次只能激活一个保留锁,但多个共享锁可以与一个保留锁共存

    这是否意味着我每次只需要生成一个线程来更新一组行?也就是说,有某种轮询线程,它决定我需要更新一些行,然后创建一个新线程来完成,但一次不能超过一个?因为它看起来就像我创建的任何其他线程一样,在第一个线程完成之前,SQLITE_都会很忙

    我理解得对吗

    顺便说一句,谢谢你迄今为止的回答,他们帮了大忙。

    我用C做了类似的事情,我上传了代码


    我希望它有用。

    开始使用SQLlite进行多线程使用时的一些步骤:

  • 确保使用多线程标志编译sqlite
  • 您必须在sqlite文件上调用open来在每个线程上创建连接,不要在线程之间共享连接
  • SQLite有一个非常保守的线程模型,当您执行写操作(包括打开即将执行插入/更新/删除的事务)时,其他线程将被阻止,直到该操作完成
  • 如果不使用事务,则事务是隐式的,因此如果启动INSERT/DELETE/UPDATE,sqlite将尝试获取独占锁,并在释放该锁之前完成该操作
  • 如果执行BEGIN EXCLUSTIONAL语句,它将在该事务中执行操作之前获取一个独占锁。提交或回滚将释放锁
  • sqlite3\u步骤、sqlite3\u prepare和其他一些调用可能会返回SQLITE\u BUSY或SQLITE\u LOCKED。SQLITE_BUSY通常意味着SQLITE需要获取锁。两个返回值之间的最大差异:
    • SQLITE\U LOCKED:如果您从sqlite3\U step语句中获取此信息,则必须在语句句柄上调用sqlite3\U reset。您应该只在第一次调用sqlite3\u步骤时得到这个结果,因此一旦调用了reset,您实际上可以“重试”sqlite3\u步骤调用。在其他操作上,它与SQLITE_BUSY相同
    • SQLITE_BUSY:不需要调用sqlite3_reset,只需在等待锁释放一段时间后重试操作
  • 退房。最简单的方法是自己进行锁定,避免在线程之间共享连接。可以找到另一个好的资源,其结论是:

  • 确保编译SQLite时使用-DTHREADSAFE=1

  • 确保每个线程都打开了数据库文件并保持其自己的sqlite结构

  • 确保处理一个或多个线程在同时访问db文件时发生冲突的可能性:适当地处理SQLITE_BUSY

  • 确保在事务中包含修改数据库文件的命令,如INSERT、UPDATE、DELETE和其他命令


  • 我意识到这是一个古老的线程,响应很好,但我最近一直在研究这个问题,并对一些不同的实现进行了有趣的分析。主要讨论了连接共享、消息传递、线程本地连接和连接池的优缺点。看看这里:

    SQLite的现代版本默认启用了线程安全。编译标志控制SQLite中是否包含代码,以使其能够在多线程环境中安全运行默认值为
    SQLITE\u THREADSAFE=1
    。这意味着。我