关于Asio异步操作执行顺序与线程安全的技术问询
Asio异步操作控制流与线程安全疑问解答
问题背景
作为Asio新手,我对异步操作的控制流存在疑惑,以下是我编写的服务器代码:
class session { ... sendMsg() { bool idle = msgQueue.empty(); msgQueue.push(msg); if (idle) send(); } send() { async_write(write_handler); } write_handler() { msgQueue.pop(); if (!msgQueue.empty()) send(); } recvMsg() { async_read(read_handler); } read_handler() { ... recvMsg(); } ... }; class server { ... start() { async_accept(accept_handler); } accept_handler() { auto client = make_shared<session>(move(socket)); client->recvMsg(); ... start(); } ... }; int main() { io_context; server srv(io_context, 22222); srv.start(); io_context.run(); return 0; }
我有两个核心疑问:
- 所有完成处理程序
accept_handler、read_handler、write_handler均在调用io_context.run()的主线程中执行,它们是否会顺序执行而非并发?进而,msgQueue的访问是顺序的,是否无需为该队列添加互斥锁? async_*函数会告知操作系统执行任务,这些任务会在其他线程中并行执行,即使多个任务同时完成,对应的完成处理程序是否仍会顺序执行,而非并发?
解答
处理程序执行顺序与msgQueue线程安全
所有完成处理程序确实会在调用io_context.run()的单个主线程内顺序执行,不会出现并发执行的情况。
默认情况下,单线程调用io_context.run()时,io_context会维护一个任务队列,所有就绪的完成处理程序都会被加入队列,然后按顺序逐个调度执行——同一时间只会有一个处理程序在运行。
因此你的msgQueue的所有操作(push、pop、empty)都是在同一个线程里按顺序进行的,不存在多线程竞态条件,完全不需要为msgQueue添加互斥锁。
异步任务完成后处理程序的执行逻辑
你对async_*函数的理解是正确的:async_*函数会将IO任务提交给操作系统,由操作系统在后台内核线程中执行IO操作。但完成处理程序的调度权完全在io_context手中。
即使多个IO任务同时完成,对应的完成处理程序也只会被加入io_context的任务队列,在调用io_context.run()的单线程中按顺序执行,不会并发运行。只有当你使用多个线程调用同一个io_context的run()方法时,处理程序才有可能在不同线程中并发执行,这时候才需要考虑线程安全问题。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

