Boost asio asio串与数据同步

Boost asio asio串与数据同步,boost-asio,Boost Asio,我发现asio关于通过strand进行同步的文档并不清楚。它只是说,在线程池设计asio应用程序中,处理程序可以在任何调用了io\u service::run()的线程中运行。使用串扭曲这些处理程序可以使它们的执行正确并发。在its中,所有的handle\u read都由strand包装,我认为Connection类中的变量,如buffer已经由strand同步,不同的线程调用handle\u read将获得最新数据,这是可以的。但是,连接类中定义了一个数据成员,这个数据成员也是由处理程序访问的

我发现asio关于通过
strand
进行同步的文档并不清楚。它只是说,在线程池设计asio应用程序中,处理程序可以在任何调用了
io\u service::run()
的线程中运行。使用
扭曲这些处理程序可以使它们的执行正确并发。在its中,所有的
handle\u read
都由
strand
包装,我认为
Connection
类中的变量,如
buffer
已经由
strand
同步,不同的线程调用
handle\u read
将获得最新数据,这是可以的。但是,
连接
类中定义了一个数据成员,这个数据成员也是由处理程序访问的,而不是由
包装的?我认为这是个问题,不是吗


在它的文档中,为什么
handle\u accept
没有被
包裹?
new\u connection\u
由多线程访问:
new\u connection\u.reset
由线程A调用,而
server::handle\u accept
由线程B调用。我想它需要在这里进行数据同步,否则线程B可能会使用一个过期的
new\u connection\u
,而它的重置尚未调用。

我想你不知何故,我们忽略了strand的含义。它不同步数据访问。它同步处理程序调用。这可以理解为“由给定的链包装的所有处理程序都不会被并发调用”

所以,您的第一个任务是:如果某个处理程序没有被strand包装,那么现在可以并发调用它。因此,它受到同步问题和/或RC的影响。注意,如果你在一个地方包装,并不意味着你是从钢筋混凝土保护;每次通话都应该这样做。因为strand不知道从其他线程调用什么,除非您使用
.wrap

第二个问题:在给定的示例中,start\u accept设置接受处理程序handle\u accept,并且handle\u accept正在设置新的接受处理程序(通过调用start\u accept)。因此,它们不会被并发调用,因为您不能创建2个或更多的异步\u accept事件。当然,如果对同一个“服务器”实例执行其他线程调用start\u accept,则此示例可能会失败,但这样做显然是错误的。

的设计方式实际上不需要

Asio的一个基本特性是,对于给定的操作,处理程序最多只能调用一次。这种行为使得异步编程的调用路径更像是一个调用链

例如,检查图示的
服务器的呼叫链
接受连接:

server::server(...)
{
  start_accept();  --.
}                    |
    .----------------'
    |      .----------------------------------------.
    V      V                                        |
void server::start_accept()                         |
{                                                   |
  new_connection_.reset(new connection(...));       |
  acceptor_.async_accept(..., handle_accept);  --.  |
}                                                |  |
    .--------------------------------------------'  |
    |                                               |
    V                                               |
void server::handle_accept(...)                     |
{                                                   |
  if (!error)                                       |
  {                                                 |
    new_connection_->start();                       |
  }                                                 |    
  start_accept();  ---------------------------------'
}
如图所示,仅存在一个异步事件链。由于不可能在
new_connection
上并发执行处理程序或操作,因此它被称为在隐式链中运行。处理程序运行的线程,
server::handle\u accept
,是无关紧要的


connection::handle\u read
调用链和关于链的更多细节都有疑问。

I根据我的经验,线程同步意味着数据和代码执行。缺少任何一个,同步将毫无意义。因为lock可以同时实现这两个功能。在这个示例中,如果串不进行数据同步,缓冲区数据成员将有问题。start_accept()和handle_accept()将在不同的线程中执行,因此为什么与数据成员“new_connection”的数据同步无关?start_accept()和handle_accept()不能同时执行。运行
start\u accept
时,没有活动的
async\u accept
,因此无法调用
handle\u accept
。另一方面,当调用
handle\u accept
时,io\u服务中不再有这样的处理程序;调用
async\u accept()
时,它将添加到
handle\u accept
的末尾。然而,有一个bug。由于
new\u connection\u->start()
未保存
new\u connection\u
shared\u ptr,它将在
async\u accept
中重写。所以你是对的,这可能会失败,但在其他地方(在连接类中)。注意这是不完整的,我知道它们不会由不同的线程同时执行。我的问题是,当线程A在线程B完成start_accept()执行后调用句柄_accept()时,如何同步共享变量“new_connection”的状态。因为线程B调用'new_connection_uu'reset(),这将改变它的状态。在没有任何显式同步的情况下,线程A如何看到这些状态的变化?由于
start\u accept()
被设计为只从对象外部启动一次,从对象内部启动多次,因此只有当
handle\u accept
准备就绪时才会调用
new\u connection\u.reset()
;而且是同一条线。如果某个线程在这个实例已经运行时调用了
start\u accept()
,那么它就有麻烦了。但这样做是用户的错误。我得到两点:1,在asio中,处理程序调用链是并发的,正如文档所说的“隐式链”。2,HTTP示例3的句柄_read不需要包装在串中,因为它构成了一个链。我说得对吗?@jean:在图示的链中,有一个异步操作链与
接受器
关联。因此,不可能并发执行与此链关联的处理程序。另一方面,这些处理程序可能与另一个链的处理程序同时运行,例如每个
连接
handle\u read
。是的,
handle\u read
中的
是不必要的,因为该链形成一个隐式链。