当只有一个线程主要使用该对象而其他线程很少使用它时,如何最小化该对象的互斥锁锁定?
How to minimize the mutex locking for an object when only 1 thread mostly uses that object and the other thread(s) use it rarely?
场景
假设有"Thread_Main"和"Thread_DB",以及共享的SQLite数据库对象。可以保证,
- "Thread_main"很少使用SQLite对象进行读取(即
SELECT()
( - "Thread_DB"大部分时间使用SQLite对象进行各种
INSERT
、UPDATE
DELETE
操作
。
为了避免数据竞争和 UB,SQLite 应该使用SQLITE_THREADSAFE=1
(默认(选项进行编译。这意味着,在每次操作之前,内部mutex
将被锁定,以便数据库在读取时不会写入,反之亦然。
"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)
问题
如上所示,在 100 多个操作中,只需要偶尔需要真正的互斥锁。但是,为了保护这种小情况,我们必须为所有操作锁定它。
问:有没有一种方法可以让"Thread_DB"大部分时间保持互斥锁,这样就不需要每次都锁定?锁定/解锁只能在"Thread_Main"请求时发生。
笔记
- 一种方法是在"Thread_DB"中排队
SELECT
。但在运行多个数据库的较大场景中,这会减慢响应速度,并且不会是实时的。无法让主线程等待它。 - 我还考虑过有一个"Thread_Main"整数/布尔变量,它将表明"Thread_Main"想要
SELECT
。现在,如果当时有任何操作在"Thread_DB"中运行,它可以解锁互斥锁。这很好。但是,如果没有在该SQLite对象上运行可写操作,则"Thread_main"将继续等待,因为"Thread_DB"中没有人可以解锁。这将再次延迟甚至挂起"Thread_Main"。
这里有一个建议:稍微修改一下你的程序,使Thread_Main
无法访问共享对象;只有Thread_DB
才能访问它。 完成此操作后,您根本不需要执行任何序列化,Thread_DB
可以完全高效地工作。
当然,美中不足的是,Thread_Main
有时确实需要与数据库对象进行交互;如果它无法访问它,它怎么能做到这一点呢?
该问题的解决方案是消息传递。 当Thread_Main
需要对数据库执行某些操作时,它应该将某种 Message 对象传递给Thread_DB
。 Message 对象应包含表征所需交互所需的所有详细信息。 当Thread_DB
收到 Message 对象时,Thread_DB
可以调用其execute(SQLite & db)
方法(或任何您想要调用它的方法(,此时可以从Thread_DB
线程的上下文中进行必要的数据插入/提取。 交互完成后,任何结果都可以存储在 Message 对象中,然后可以将 Message 对象传递回主线程,以便主线程处理结果。 (主线程可以阻止等待消息发回,也可以继续异步运行到数据库线程,这取决于你(
- 即发即弃 std::线程对象清理自身
- C++:处理线程本地对象销毁
- 结束另一个线程中使用的对象的生存期
- 通过插槽和信号在不同线程中的两个qt对象之间进行通信
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 线程调用的函数对对象删除是否安全?
- 将对象传递给多线程对象 Qt
- asio 链对象线程安全吗?
- 如何初始化大线程本地对象?
- 在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
- 当只有一个线程主要使用该对象而其他线程很少使用它时,如何最小化该对象的互斥锁锁定?
- 如何将对象从类线程传递到帖子?
- 将抽象对象从主线程发送到其他线程
- 在 While 循环中重用对象的多线程
- 本地静态函数对象线程安全的初始化
- 对于 c++11 之前的编译器,返回本地静态对象线程是否安全
- 从一个对象线程中使用 const 方法是否安全
- C++流对象线程安全
- 使STL对象线程安全的标准方法
- QT多线程和移动对象线程创建后