我有一个应用程序,其中有许多SQLite数据库的读者并行执行,每个读者都在自己的进程中。进程可以fork ...并且能够在建立SQLite连接后执行此操作。
我想编写一个fork处理程序,以便在父进程分叉时,子进程中的所有SQLite状态都“刷新”...这意味着所有准备好的语句,数据库连接和其他资源都是立即的没有清理就丢弃了。
作为一个库,SQLite管理自己的内存和其他资源,因此理论上是可行的。
实际上,我想要做的是在分叉时复制非SQLite应用程序状态,但如果程序已经通过exec*
而不是fork
开始执行,则具有SQLite状态。
如果可能的话,我想做的事情会是这样的:
void sqlite_refresh(void)
{
// discard all sqlite-specific state
// make all sqlite3_db, sqlite3_stmt &c pointers NULL
return;
}
// call this code somewhere
pthread_atfork(
/* prepare */ NULL,
/* parent */ NULL,
/* child */ sqlite_refresh
);
在SQLite网站上,有一些关于不使用fork的评论,但它似乎是假设程序员打算在分叉后与子进程中的SQLite库进行交互而编写的。
SQLite在its documentation中就使用fork:
提出以下不祥警告不要打开SQLite数据库连接,然后fork(),然后尝试 在子进程中使用该数据库连接。各类 将导致锁定问题,您很容易就会陷入腐败 数据库。 SQLite不是为支持这种行为而设计的。任何 必须在中打开子进程中使用的数据库连接 子进程,不是从父进程继承的。
甚至不要在来自孩子的数据库连接上调用sqlite3_close() 如果在父级中打开了连接,则进行处理。这是安全的 关闭底层文件描述符,但是sqlite3_close() 接口可能会调用将删除内容的清除活动 从父母下面,导致错误,甚至可能导致数据库 损坏。
它说here
在Unix下,你不应该跨越一个开放的SQLite数据库 fork()系统调用子进程。
答案 0 :(得分:0)
子进程不能使用从父进程获取的连接/语句对象任何。这意味着您的sqlite_refresh()
函数必须为空,或者它只是将所有指针设置为NULL。
(这意味着内存泄露。)
在分叉时没有开放连接会更好。