Boost库之asio io_service以及run、run_one、poll、poll_one区别

简介: 一、io_service的作用 io_servie 实现了一个任务队列,这里的任务就是void(void)的函数。Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。

一、io_service的作用

io_servie 实现了一个任务队列,这里的任务就是void(void)的函数。Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列。

 

二、Io_servie的接口

提供的接口有run、run_one、poll、poll_one、stop、reset、dispatch、post,最常用的是run、post、stop

三、Io_servie 实现代码的基本类结构:

Io_servie是接口类,为实现跨平台,采用了策略模式,所有接口均有impl_type实现。根据平台不同impl_type分为

  win_iocp_io_service Win版本的实现,这里主要分析Linux版本。

  task_io_service 非win平台下的实现,其代码结构为:

  detail/task_io_service_fwd.hpp 简单声明task_io_service名称

  detail/task_io_service.hpp 声明task_io_service的方法和属性

  detail/impl/task_io_service.ipp 具体实现文件

  队列中的任务类型为opertioan,原型其实是typedef task_io_service_operation operation,其实现文件在detail/task_io_service_operation.hpp中,当队列中的任务被执行时,就是task_io_service_operation:: complete被调用的时候。

四、Dispatch和post的区别

Post一定是PostQueuedCompletionStatus并且在GetQueuedCompletionStatus 之后执行。

Dispatch会首先检查当前thread是不是io_service.run/runonce/poll/poll_once线程,如果是,则直接运行。

五、Io_servie::run方法的实现

         Run方法执行队列中的所有任务,直到任务执行完毕。

  run方法首先构造一个idle_thread_info,和first_idle_thread_类型相同,即通过first_idle_thread_将所有线程串联起来,它这个串联不是立即串联的,当该线程无任务可做是加入到first_idle_thread_的首部,有任务执行时,从first_idle_thread_中断开。这很正常,因为first_idle_thread_维护的是当前空闲线程。

  加锁,循环执行do_one方法,直到do_one返回false

  do_one每次执行一个任务。首先检查队列是否为空,若空将此线程追加到first_idle_thread_的首部,然后阻塞在条件变量上,直到被唤醒。

  当被唤醒或是首次执行,若stopped_为true(即此时stop方法被调用了),返回0

  队列非空,pop出一个任务,检查队列无任务那么简单的解锁,若仍有,调用wake_one_thread_and_unlock尝试唤醒其他空闲线程执行。然后执行该任务,返回1.

  实际上在执行队列任务时有一个特别的判断if (o ==&task_operation_),那么将会执行task_->run,task_变量类型为reactor,在linux平台实现为epoll_reactor,实现代码文件为detail/impl/epoll_reactor.ipp,run方法实际上执行的是epoll_wait,run阻塞在epoll_wait上等待事件到来,并且处理完事件后将需要回调的函数push到io_servie的任务队列中,虽然epoll_wait是阻塞的,但是它提供了interrupt函数,该interrupt是如何实现的呢,它向epoll_wait添加一个文件描述符,该文件描述符中有8个字节可读,这个文件描述符是专用于中断epoll_wait的,他被封装到select_interrupter中,select_interrupter实际上实现是eventfd_select_interrupter,在构造的时候通过pipe系统调用创建两个文件描述符,然后预先通过write_fd写8个字节,这8个字节一直保留。在添加到epoll_wait中采用EPOLLET水平触发,这样,只要select_interrupter的读文件描述符添加到epoll_wait中,立即中断epoll_wait。

  Run方法的原则是:

  有任务立即执行任务,尽量使所有的线程一起执行任务

  若没有任务,阻塞在epoll_wait上等待io事件

  若有新任务到来,并且没有空闲线程,那么先中断epoll_wait,先执行任务

  若队列中有任务,并且也需要epoll_wait监听事件,那么非阻塞调用epoll_wait(timeout字段设置为0),待任务执行完毕在阻塞在epoll_wait上。

  几乎对线程的使用上达到了极致。

  从这个函数中可以知道,在使用ASIO时,io_servie应该尽量多,这样可以使其epoll_wait占用的时间片最多,这样可以最大限度的响应IO事件,降低响应时延。但是每个io_servie::run占用一个线程,所以io_servie最佳应该和CPU的核数相同。

六、Io_servie::stop的实现

  加锁,调用stop_all_threads

  设置stopped_变量为true,遍历所有的空闲线程,依次唤醒

  task_interrupted_设置为true,调用task_的interrupt方法。

七、reset和stop

文档中reset的解释是重置io_service以便下一次调用。

 run,run_one,poll,poll_one是被stop掉导致退出,或者由于完成了所有任务(正常退出)导致退出时,在调用下一次 run,run_one,poll,poll_one之前,必须调用此函数。reset不能在run,run_one,poll,poll_one正在运行时调用。如果是消息处理handler(用户代码)抛出异常,则可以在处理之后直接继续调用 io.run,run_one,poll,poll_one。

八、run,run_one,poll,poll_one的区别

run其实就是一直循环执行do_one,并且是以阻塞方式进行的(参数为true),而run_one同样是以阻塞方式进行的,但只执行一次do_one;poll和run几乎完全相同,只是它是以非阻塞方式执行do_one(参数为false),poll_one是以非阻塞方式执行一次do_one。

run,run_one,及poll,poll_one的实现代码,如下:

 

[cpp]  view plain  copy
 
  1. // Run the event loop until stopped or no more work.  
  2. size_t run(boost::system::error_code& ec)  
  3. {  
  4.   if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)  
  5.   {  
  6.     stop();  
  7.     ec = boost::system::error_code();  
  8.     return 0;  
  9.   }  
  10.   
  11.   call_stack<win_iocp_io_service>::context ctx(this);  
  12.   
  13.   size_t n = 0;  
  14.   while (do_one(true, ec))  
  15.     if (n != (std::numeric_limits<size_t>::max)())  
  16.       ++n;  
  17.   return n;  
  18. }  
  19.   
  20. // Run until stopped or one operation is performed.  
  21. size_t run_one(boost::system::error_code& ec)  
  22. {  
  23.   if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)  
  24.   {  
  25.     stop();  
  26.     ec = boost::system::error_code();  
  27.     return 0;  
  28.   }  
  29.   
  30.   call_stack<win_iocp_io_service>::context ctx(this);  
  31.   
  32.   return do_one(true, ec);  
  33. }  
  34.   
  35. // Poll for operations without blocking.  
  36. size_t poll(boost::system::error_code& ec)  
  37. {  
  38.   if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)  
  39.   {  
  40.     stop();  
  41.     ec = boost::system::error_code();  
  42.     return 0;  
  43.   }  
  44.   
  45.   call_stack<win_iocp_io_service>::context ctx(this);  
  46.   
  47.   size_t n = 0;  
  48.   while (do_one(false, ec))  
  49.     if (n != (std::numeric_limits<size_t>::max)())  
  50.       ++n;  
  51.   return n;  
  52. }  
  53.   
  54. // Poll for one operation without blocking.  
  55. size_t poll_one(boost::system::error_code& ec)  
  56. {  
  57.   if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)  
  58.   {  
  59.     stop();  
  60.     ec = boost::system::error_code();  
  61.     return 0;  
  62.   }  
  63.   
  64.   call_stack<win_iocp_io_service>::context ctx(this);  
  65.   
  66.   return do_one(false, ec);  
  67. }  
  68. do_one的函数原型  
  69. size_t do_one(bool block, boost::system::error_code& ec)  
  70. {  
  71. …  
  72. BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, &completion_key, &overlapped, block ? timeout : 0);  
  73. …  
  74. }  
目录
相关文章
|
30天前
|
缓存 Linux API
文件IO和标准IO的区别
文件IO和标准IO的区别
20 2
|
2月前
|
测试技术 C++ iOS开发
c++IO库详细介绍
前言 简单分享一下c++ IO相关的一些知识点,希望对大家有用
48 0
|
3月前
|
存储 网络协议
TCP服务器 IO多路复用的实现:select、poll、epoll
TCP服务器 IO多路复用的实现:select、poll、epoll
34 0
|
4月前
|
Linux 编译器 vr&ar
Linux基础IO【软硬链接与动静态库】
Linux基础IO【软硬链接与动静态库】
44 1
|
1月前
|
调度 数据库 Python
Python中的并发编程:使用asyncio库实现异步IO
传统的Python程序在面对IO密集型任务时,往往会遇到性能瓶颈。本文将介绍如何利用Python中的asyncio库,通过异步IO的方式来提升程序的效率和性能,让你的Python程序能够更好地处理并发任务。
|
2月前
|
大数据 程序员 Python
Python中的异步编程:使用asyncio库实现高效IO操作
传统的同步编程模式在处理IO密集型任务时效率较低,因此异步编程成为了解决这一问题的关键。本文将介绍如何利用Python中的asyncio库实现异步编程,以及如何利用异步特性提高IO操作的效率,让你的程序更加响应迅速。
|
2月前
|
存储 Rust 安全
Rust标准库概览:集合、IO、时间与更多
本文将带领读者深入了解Rust标准库中的一些核心模块,包括集合类型、输入/输出处理、时间日期功能等。我们将通过实例和解释,探讨这些模块如何使Rust成为高效且安全的系统编程语言。
|
3月前
|
数据采集 大数据 API
探索Python异步编程:解密异步IO库的奥秘
本文将深入探讨Python异步编程的核心概念,并重点介绍异步IO库(例如asyncio)的原理和应用。通过对异步编程的理解和实践,我们可以提高Python程序的性能和响应能力,从而提升用户体验。本文将带您走进异步编程的世界,揭示其中的神奇之处,助您在技术领域中更上一层楼。
|
3月前
|
vr&ar 开发者 Python
探索未来的现实世界:混合现实(AR)与增强现实(VR)技术的应用Python异步编程:解放性能的重要利器——异步IO库深入解析
在当今科技飞速发展的时代,混合现实(AR)和增强现实(VR)技术正迅速改变着我们对现实世界的认知和体验。本文将介绍这两种技术的基本原理以及它们在不同领域的广泛应用,包括教育、医疗、旅游、娱乐等。混合现实和增强现实技术为我们带来了全新的沉浸式体验,将人与数字世界融合在一起,为未来的现实世界带来无限可能。 在当今信息爆炸的时代,高效的编程方式成为开发者追求的目标。Python异步编程与其强大的异步IO库(例如asyncio)成为了解放性能的重要利器。本文将深入解析Python异步编程以及异步IO库的原理和使用方法,帮助读者进一步掌握这一技术,提升开发效率。
|
3月前
|
关系型数据库 容器
portainer.io 面板pull image 和 run mariadb
portainer.io 面板pull image 和 run mariadb
27 0