C++ SQLite序列化模式问题
我读了好几页,对发生的事情有了一个好的想法,但我有几个问题想确定一下 我的程序使用-DTHREADSAFE=1编译选项,在接收到来自用户或我的网络的数据库请求时分叉选择、删除、插入、更新,然后子进程处理各种数据库任务,并在需要时中继消息,等等 目前,我的数据库没有设置为并发性,我不会说这是一个主要的设计缺陷,但这不是目前的重点,假设我有一个函数,它可以打印我的表分类账中的所有条目,如下所示C++ SQLite序列化模式问题,c++,multithreading,sqlite,mutex,C++,Multithreading,Sqlite,Mutex,我读了好几页,对发生的事情有了一个好的想法,但我有几个问题想确定一下 我的程序使用-DTHREADSAFE=1编译选项,在接收到来自用户或我的网络的数据库请求时分叉选择、删除、插入、更新,然后子进程处理各种数据库任务,并在需要时中继消息,等等 目前,我的数据库没有设置为并发性,我不会说这是一个主要的设计缺陷,但这不是目前的重点,假设我有一个函数,它可以打印我的表分类账中的所有条目,如下所示 void PersonalDataBase::printAllEntries() { //get all
void PersonalDataBase::printAllEntries()
{
//get all entries
const char query [] = "select * from LEDGER";
sqlite3_stmt *stmt;
int error
try
{
if ((error = sqlite3_prepare(publicDB, query, -1, &stmt, 0 )) == SQLITE_OK)
{
int ctotal = sqlite3_column_count(stmt);
int res = 0;
while ( 1 )
{
res = sqlite3_step(stmt);
if ( res == SQLITE_ROW )
{
Entry *temp = loadBlockRow(stmt);
string from, to;
from = getNameForHash(temp -> from);
to = getNameForHash(temp -> to);
temp -> setFromOrTo(from, 0);
temp -> setFromOrTo(to, 1);
temp -> printEntry();
printlnEnd();
delete temp;
}
else if ( res == SQLITE_DONE || res==SQLITE_ERROR)
{
if (res == SQLITE_ERROR) { throw res; }
sqlite3_finalize(stmt);
break;
}
}
}
//problems
else
{
throw error;
}
}
catch (int err)
{
sqlite3_finalize(stmt);
setupOutput();
cout << "Database Error: " << sqlite3_errmsg(publicDB) << ", Error Code: " << (int) error << endl;
cout << "Did Not Find Values Try Again After Fixing Problems Above." << endl;
printlnEnd();
}
println("Done!");
}
我的setupOutput、printlend、println,所有这些都有助于我使用“非阻塞”键盘i/o,它们可以按照我的要求工作。让我们不要在这里担心它们,并将它们视为对cout的调用
好的,现在我想有4种选择
在我的try/catch前后一段时间,然后在catch check if err=5中,如果是这样,我需要设置一个sqlite3\u busy\u处理程序,并让它在返回SQLITE\u OK并清除了我在while/try过程中重复的所有旧变量后等待阻止当前操作的任何内容,因为现在一次只能设置其中一个,比如说,Child1正在做一个大的写操作,child2和child3试图在第一个孩子的写操作的基础上并发地说读和更新,所以如果这个函数返回一个SQLITE_BUSY,我会打印出一个错误,然后重新启动我的while循环,重新启动这个函数,当然,在我完成我的旧语句之后,并清除了可能已经创建的任何局部对象,如果这是一个正确的思路
我是否应该设置一个递归互斥体,比如说将其拧到SQLite自己的锁定机制,将其设置为跨进程共享,然后一次只允许对数据库执行一个操作?对于在小范围内使用我的应用程序来说,这似乎不是一个坏的选择,但是我读到了很多关于使用递归互斥的警告,我想知道这是否是最好的选择,正如许多帖子所说,自己处理互斥。然而,我不能同时读取,这有点痛苦
使用选项1,但不要使用SQLite busy处理程序,只需随机调用usleep,清理数据,然后重新启动即可
在涉及我的数据库的任何函数之前/之后,分别使用beginimmediate/COMMIT的sqlite3_exec,在这两条语句之间的代码期间锁定数据库。因此,canor中的任何内容至少都不会返回SQLITE_BUSY,那么如果我的BEGIN IMMEDIATE返回BUSY,那么只要一切设置正确,它应该是唯一的一个,我使用sqlite3_BUSY_处理程序,老实说,如果一次只有一个进程可以使用它,那么它看起来很烦人。。。或者使用usleep的随机数,假设这个数字相当大,1mil=1秒,1-20个进程之间重叠的机会非常小,因此每个进程都会不断尝试以随机间隔重新锁定数据库,以实现其自身的目的
有更好的办法吗?或者哪一个是最好的
安装了SQLite的内部忙处理程序,该处理程序已经休眠了或多或少的随机次数;没有必要编写自己的处理程序 使用您自己的锁定机制将比随机等待更有效,但前提是您拥有读写器锁定 BEGIN或BEGIN IMMEDIATE确保同一事务中的任何其他语句都不能运行到锁中,但仅当IMMEDIATE用于写入的事务时
<>为了允许并发的读者和作者,考虑使用。但是这也不允许有多个写入程序。但是如果两个进程“冲突”都调用sqlite3\u busy\u timeout,那么如果我没有弄错的话,原始调用程序将返回SQLITE\u busy,那么我是否需要创建一个处理程序来处理这个问题呢?好的,那么在修改数据时只使用IMMEDIATE关键字?这里的问题是,如果有人当前正在读取行,而另一个进程决定调用IMMEDIATE,那么IMMEDIATE将一直处于SQLITE_忙碌状态,直到读取器完成之后,或者它将停止读取?如果它停止了我对数据的读取/打印,那么老实说,即使是读取事务也最好锁定您可以使用sqlite3命令行shell测试立即锁定,该命令行shell也具有.timeout.awesome!我最终使用了WAL模式和递归互斥锁对db进行写/删除/等操作,现在似乎一切正常!