SQLite和安全分叉

时间:2018-06-09 04:13:00

标签: c sqlite

我有一个应用程序,其中有许多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()系统调用子进程。

1 个答案:

答案 0 :(得分:0)

子进程不能使用从父进程获取的连接/语句对象任何。这意味着您的sqlite_refresh()函数必须为空,或者它只是将所有指针设置为NULL。 (这意味着内存泄露。)

在分叉时没有开放连接会更好。