Asio 异步和并发

Posted

技术标签:

【中文标题】Asio 异步和并发【英文标题】:Asio async and concurrency 【发布时间】:2009-12-16 15:49:36 【问题描述】:

我正在用boost::asio 编写一些代码,使用异步TCP 连接。我不得不承认我对此有些怀疑。所有这些都与并发有关。以下是一些:

如果我在同一个套接字上启动两个或多个async_write 而没有等待第一个完成,会发生什么?处理程序(和async_write)会重叠还是asio 提供序列化和同步?

上述问题与async_connectasync_read 相同。一般来说,从不同线程调用这些函数是否安全(我不是在谈论使用不同的缓冲区,这是另一个问题......)。

【问题讨论】:

【参考方案1】:

根据您的问题,我假设您有一个 io_service 实例,并且您想从多个线程对其调用 async_write()

async_write() 最终调用io_servicepost() 方法,该方法又会获取锁并将要写入的位推入工作队列,确保位不会被交错写入。这些位最终将被写出,并且保存它们的基础数据结构(char 数组或其他)必须保持有效,直到您收到表示写入已完成的回调。如果您使用与完成处理程序完全相同的回调函数,您将无法知道这两个写入中的哪一个导致该函数被调用,并且如果该函数执行任何非线程安全的操作,则行为可能未定义或不正确。处理这种情况的一种流行方法是拥有一个作为完成处理程序的结构实例(只需重载 call () 运算符):您可以设置结构的属性以表示它对应于哪个写入,然后查阅这些值当调用完成处理程序时。

但是,如果没有共享锁,您无法控制哪个线程实际执行其async_write() 方法。事实上,即使你启动了两个线程,让一个线程立即调用async_write(),让另一个线程休眠一个小时,然后调用async_write(),你仍然不能保证操作系统没有愚蠢地调度你的线程并且首先执行第二个线程的调用。 (这个例子是病态的,但这一点是普遍有效的。)

同样的情况也适用于async_read()。您当然可以交错调用(即在调用完成处理程序之前先执行一个async_read(),然后再执行另一个),但不能保证在没有一些外部手段来确保这一点的情况下会按照您想要的顺序执行。

【讨论】:

【参考方案2】:

如果您在同一个套接字上启动两个异步操作,它们可以按任意顺序发生。只要他们使用不同的缓冲区,它就是“安全的”,因为它不会崩溃,但这种行为几乎不是你想要的。

【讨论】:

以上是关于Asio 异步和并发的主要内容,如果未能解决你的问题,请参考以下文章

Boost.Asio 的同步和并发数据结构模式

将音频源(并发)动态发送到 ASIO 设备上的特定通道

在 Windows 上使用 Boost.Asio 的半并发 ICMP ping

多线程和Boost::Asio

Boost Asio总结class strand

boost的并发库