10

我正在尝试确定我对数据库的 sqlite 访问是否在 iOS 上是线程安全的。我正在编写一个非 App Store 应用程序(或者可能是一个启动守护程序),因此 Apple 的批准不是问题。有问题的数据库是内置的sms.db,所以操作系统肯定也在访问这个数据库进行读写。我只想能够安全地阅读它。

我读过这篇关于使用 sqlite 从多个进程中读取的内容:

多个进程可以同时打开同一个数据库。多个进程可以同时执行 SELECT。但是,任何时候只有一个进程可以对数据库进行更改。

我知道线程安全可以从 sqlite 编译出来,并且sqlite3_threadsafe()可以用来测试这一点。在 iOS 5.0.1 上运行

int safe = sqlite3_threadsafe();

结果为 2。 据此,这意味着互斥锁是可用的。但是,这并不一定意味着它正在使用中。

我并不完全清楚线程安全是否在每个连接、每个数据库或全局基础上动态启用。

我也读过这个。看起来sqlite3_config()可以用来启用安全的多线程,但当然,我无法控制或了解操作系统本身可能如何使用此调用(是吗?)。如果我要在我的应用程序中再次进行该调用,是否可以安全地读取数据库,或者它是否只会解除我的应用程序中使用相同sqlite3数据库句柄的多个线程的并发访问冲突?

无论如何,我的问题是...

我可以安全地读取这个也被 iOS 访问的数据库吗?如果可以,如何?

4

2 回答 2

12

我从未使用过 SQLite,但我花了相当多的时间阅读它的文档,因为我计划在未来使用它(而且文档很有趣)。我想说线程安全与多个进程是否可以同时访问同一个数据库文件无关。SQLite,无论处于何种线程模式,都会锁定数据库文件,这样多个进程可以同时从数据库中读取,但只有一个可以写入。

线程安全仅影响您的进程如何使用 SQLite。没有任何线程安全,您只能从一个线程调用 SQLite 函数。但它仍然应该在写入之前获得一个独占锁,这样其他进程就不会破坏数据库文件。如果您使用多个线程,线程安全只是保护进程内存中的数据不被损坏。因此,我认为您不必担心另一个进程(在本例中为 iOS)对 SQLite 数据库的操作。

编辑:澄清一下,任何时候你写入数据库,包括一个普通的INSERT// UPDATEDELETE它都会自动获取一个独占锁,写入数据库,然后释放锁。(实际上它在写入之前需要一个共享锁,然后是保留锁,然后是挂起锁,然后是排他锁。)默认情况下,如果数据库已经被锁定(比如来自另一个进程),那么 SQLite 将返回 SQLITE_BUSY 而无需等待. 你可以打电话sqlite3_busy_timeout()告诉它等待更长时间。

于 2012-07-07T01:15:56.570 回答
2

我不认为这对你来说是新闻,但有一些想法:

在启用多线程(序列化或多线程)方面,一般建议是可以调用sqlite3_config()(但您可能必须首先按照文档中的建议或在此处讨论的SO进行关闭)以启用排序你想要的多线程。不过,这在这里的用处可能会降低,因为您无法控制 iOS 请求 sqlite 和/或此数据库的访问类型。

因此,我会认为,从学术角度来看,读取这个系统数据库是不安全的(因为正如你所说,你不能保证操作系统在做什么)。但如果 iOS 使用默认模式打开数据库,我不会感到惊讶,所以从更务实的角度来看,你可能会没事。

显然,对于大多数关注单个应用程序中的多线程访问的用户来说,最好的建议是绕过sqlite3_config()愚蠢的做法,只需确保通过您自己的 GCD 串行队列进行协调访问(即,拥有一个专用队列,所有数据库交互都通过该队列进行)通过,优雅地完全消除了多线程问题)。遗憾的是,这不是一个选项,因为您正在尝试协调数据库与 iOS 本身的交互。

于 2012-06-16T17:45:59.380 回答