假设具有共享的SQLite数据库对象的“ Thread_Main”和“ Thread_DB”。保证,
SELECT()
)INSERT
,UPDATE
,DELETE
操作为了避免数据争用和UB,SQLite应该使用SQLITE_THREADSAFE=1
(默认)选项进行编译。这意味着在每次操作之前,内部mutex
将被锁定,从而使DB在读取时不会写入,反之亦然。
"Thread_Main" "Thread_DB" no. of operation on DB
============= =========== ======================
something INSERT 1
something UPDATE 2
something DELETE 3
something INSERT 4
... ... ... (collapsed)
something INSERT 500
something DELETE 501
... ... ... (collapsed)
something UPDATE 1000
something UPDATE 1001
... ... ... (collapsed)
SELECT INSERT 1200 <--- here is a serious requirement of mutex
... ... ... (collapsed)
如上所示,在数百次操作中,仅偶尔需要真正的互斥量。但是,为了保护这种小情况,我们必须为所有操作锁定它。
问题:是否有一种方法可以使“ Thread_DB”在大多数时间保持互斥量,从而不需要每次锁定?仅当“ Thread_Main”请求时才可以进行锁定/解锁。
SELECT
排队。但是在运行多个数据库的较大场景中,这将减慢响应速度,而且不是实时的。无法让主线程等待它。SELECT
。现在,如果那时“ Thread_DB”中正在运行任何操作,则可以解锁互斥锁。这可以。但是,如果在该SQLite对象上没有可写操作正在运行,则“ Thread_main”将一直等待,因为“ Thread_DB”中没有人可以解锁。这将再次延迟甚至挂起“ Thread_Main”。这里是一个建议:对程序进行一些修改,以使Thread_Main
对共享库具有no访问权限;只有Thread_DB
可以访问它。完成此操作后,您将根本不需要进行任何序列化,并且Thread_DB
可以完全有效地工作。
美中不足的是,有时Thread_Main
确实需要与DB对象进行交互;如果它无权访问它怎么办?
该问题的解决方案是消息传递。当Thread_Main
需要对数据库执行某些操作时,应将某种Message对象传递给Thread_DB
。 Message对象应包含表征所需交互的所有必要详细信息。当Thread_DB
收到Message对象时,Thread_DB
可以调用其execute(SQLite & db)
方法(或任何您想调用的方法),这时可以在Thread_DB
线程的上下文中进行必要的数据插入/提取。交互完成后,任何结果都可以存储在Message对象内部,然后可以将Message对象传递回主线程,以便主线程处理结果。 (主线程可以阻止等待消息发送回,或者继续与DB线程异步操作,这取决于您)
这里是一个建议:对程序进行一些修改,以便Thread_Main
对共享库具有no