boost.asio - 如果在不同的异步处理程序之间共享数据库类型对象,我是不是需要使用锁?

Posted

技术标签:

【中文标题】boost.asio - 如果在不同的异步处理程序之间共享数据库类型对象,我是不是需要使用锁?【英文标题】:boost.asio - do i need to use locks if sharing database type object between different async handlers?boost.asio - 如果在不同的异步处理程序之间共享数据库类型对象,我是否需要使用锁? 【发布时间】:2014-10-25 10:10:29 【问题描述】:

我正在为一个项目制作一个小型服务器,我有一个日志处理程序类,其中包含一个实现为映射的日志和一些对其进行操作的方法(添加条目、刷新到磁盘、提交等)

此对象在服务器类中实例化,我将地址传递给会话,以便每个会话都可以向其添加条目。

会话是异步的,日志写入将发生在 async_read 回调中。我想知道这是否会成为问题,是否需要使用锁?

地图格式为map<transactionId map<sequenceNum, pair<head, body>>,每个会话将访问不同的transactionId,因此据我所知应该没有冲突。同样假设地,如果它们都写入内存中的同一个位置 - 足够大以至于操作不会是原子的;我需要锁吗?据我了解,每个异步方法都会分派一个线程来处理操作,这会让我假设是的。同时,我读到异步函数的一大用途是不需要同步原语。所以我有点困惑。

第一次完全使用 ASIO 或任何类型的异步函数,我不是一个非常有经验的编码器。我希望这个问题是有道理的!到目前为止,代码似乎运行良好,但如果它是正确的,我很好奇。

谢谢!

【问题讨论】:

【参考方案1】:

异步处理程序只会在通过run()run_one()poll()poll_one() 处理io_service 事件循环的应用程序线程中调用。 documentation 声明:

只会从当前正在调用io_service::run() 的线程中调用异步完成处理程序。

因此,对于非线程安全的共享资源:

如果应用程序代码只有一个线程,则既没有并发也没有竞争条件。因此,不需要额外的同步形式。 Boost.Asio 将此称为implicit strand。 如果应用程序代码有多个线程处理事件循环并且共享资源只能在处理程序中访问,则需要进行同步,因为多个线程可能会尝试同时访问共享资源。要解决此问题,可以: 通过同步原语(例如互斥锁)保护对共享资源的调用。这个question 涵盖了在处理程序中使用互斥锁。 对wrap() ReadHandlers 使用相同的链。 strand 将阻止并发调用通过它调度的处理程序。有关 strands 使用的更多详细信息,特别是对于组合操作,例如 async_read(),请考虑阅读 this 答案。 与其将整个 ReadHandler 发布到链中,不如将与共享资源的交互限制为一组特定的函数,并且这些函数作为 CompletionHandler 发布到同一链中。此解决方案与之前的解决方案之间的细微差别在于同步的粒度。 如果应用程序代码有多个线程,并且从处理事件循环的线程和不处理事件循环的线程访问共享资源,则需要使用同步原语,例如互斥锁。

此外,即使共享资源足够小,写入和读取始终是原子的,人们也应该更喜欢使用显式和适当的同步。例如,尽管写入和读取可能是原子的,但没有适当的内存防护来保证内存可见性,即使实际内存已经发生,线程也可能不会观察到内存中的机会。 Boost.Asio 将执行正确的memory barriers 以保证可见性。有关 Boost.Asio 和内存屏障的更多详细信息,请考虑阅读 this 答案。

【讨论】:

以上是关于boost.asio - 如果在不同的异步处理程序之间共享数据库类型对象,我是不是需要使用锁?的主要内容,如果未能解决你的问题,请参考以下文章

boost::asio::io_service类

boost--asio

关于何时在 Boost.Asio 中调用处理程序

boost asio中io_service类的几种使用

Boost Asio初探

boost::asio 学习