• boost------asio库的使用1(Boost程序库完全开发指南)读书笔记


    asio库基于操作系统提供的异步机制,采用前摄器设计模式(Proactor)实现了可移植的异步(或者同步)IO操作,而且并不要求多线程和锁定,有效地避免了多线程编程带来的诸多有害副作用。


    目前asio主要关注于网络通信方面,使用大量的类和函数封装了socket API,支持TCP、TCMP、UDP等网络通信协议。但asio的异步操作并不局限于网络编程,它还支持串口读写、定时器、SSL等功能,而且asio是一个很好的富有弹性的框架,可以扩展到其他有异步操作需要的领域

     


    概述

    asio库基于前摄器模式封装了操作系统的select、poll/epoll、kqueue、overlapped I/O等机制,实现了异步IO模型。它的核心类io_service,相当于前摄器模式中的Proactor角色,asio的任何操作都需要有io_service的参与。


    在同步模式下,程序发起一个IO操作,向io_service提交请求,io_service把操作转交给操作系统,同步地等待。当IO操作完成时,操作系统通知io_service,然后io_service再把结果发回给程序,完成整个同步流程。这个处理流程与多线程的join()等待方式很相似。


    在异步模式下,程序除了要发起的IO操作,还要定义一个用于回调的完成处理函数。io_service同样把IO操作转交给操作系统执行,但它不同步等待,而是立即返回。调用io_service的run()成员函数可以等待异步操作完成,当异步操作完成时io_service从操作系统获取执行结果,调用完成处理函数。


    asio不直接使用操作系统提供的线程,而是定义了一个自己的线程概念:strand,它保证在多线程的环境中代码可以正确地执行,而无需使用互斥量。io_service::strand::wrap()函数可以包装一个函数在strand中执行。


    asio库使用system库的error_code和system_error来表示程序运行的错误。

     

    定时器


    定时器是asio库里最简单的一个IO模型示范,提供等待时间终止的功能,通过它我们可以快速熟悉asio的基本使用方法:

    同步定时器

    #include "stdafx.h"
    #include "boost/asio.hpp"
    #include "boost/date_time/posix_time/posix_time.hpp"
    #include "iostream"
    using namespace std;
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	boost::asio::io_service ios;	// 所以的asio程序必须要有一个io_service对象
    
    	// 定时器io_service作为构造函数参数,两秒钟之后定时器终止
    	boost::asio::deadline_timer t(ios, boost::posix_time::seconds(2));
    
    	cout << t.expires_at() << endl; // 查看终止的绝对事件
    
    	t.wait();						// 调用wait同步等待
    	cout << "hello asio" << endl;
    
    	return 0;
    }
    

    可以把它与thread库的sleep()函数对比研究一下,两者都是等待,但内部机制完成不同:thread库的sleep()使用了互斥量和条件变量,在线程中等待,而asio则是调用了操作系统的异步机制,如select、epoll等完成的。

    异步定时器

    下面的是异步定时器,代码大致与同步定时器相等,增加了回调函数,并使用io_service.run()和定时器的async_wait()方法

    #include "stdafx.h"
    #include "boost/asio.hpp"
    #include "boost/date_time/posix_time/posix_time.hpp"
    #include "iostream"
    using namespace std;
    
    
    void Print(const boost::system::error_code& error)
    {
    	cout << "hello asio" << endl;
    }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	boost::asio::io_service ios;	// 所以的asio程序必须要有一个io_service对象
    
    	// 定时器io_service作为构造函数参数,两秒钟之后定时器终止
    	boost::asio::deadline_timer t(ios, boost::posix_time::seconds(2));
    
    	t.async_wait(Print);						// 调用wait异步等待
    
    	cout << "it show before t expired." << endl;
    
    	ios.run();
    
    	return 0;
    }
    

    代码的前两行与同步定时器相同,这是所有asio程序基本的部分。重要的是异步等待async_wait(),它通知io_service异步地执行io操作,并且注册了回调函数,用于在io操作完成时由事件多路分离器分派返回值(error_code)调用


    最后必须调用io_service的run()成员函数,它启动前摄器的事件处理循环,阻塞等待所有的操作完成并分派事件。如果不调用run()那么虽然操作被异步执行了,但没有一个等待它完成的机制,回调函数将得不到执行机会。

    异步定时器使用bind

    异步定时器中由于引入了回调函数,因此产生了很多的变化,可以增加回调函数的参数,使它能够做更多的事情。但async_wait()接受的回调函数类型是固定的,必须使用bind库来绑定参数以适配它的接口

       下面实现一个可以定时执行任意函数的定时器AsynTimer(asyctimer),它持有一个asio定时器对象和一个计数器,还有一个function对象来保存回调函数

    #include "stdafx.h"
    #include "boost/asio.hpp"
    #include "boost/date_time/posix_time/posix_time.hpp"
    #include "boost/bind.hpp"
    #include "boost/function.hpp"
    #include "iostream"
    using namespace std;
    
    
    class AsynTimer
    {
    public:
    	template<typename F>								// 模板类型,可以接受任意可调用物
    	AsynTimer(boost::asio::io_service& ios, int x, F func)
    		:f(func), count_max(x), count(0),				// 初始化回调函数和计数器
    		t(ios, boost::posix_time::millisec(500))		// 启动计时器
    	{
    		t.async_wait(boost::bind(&AsynTimer::CallBack,  // 异步等待计时器
    			this, boost::asio::placeholders::error));	// 注册回调函数
    	}
    
    	void CallBack(const boost::system::error_code& error)
    	{
    		if (count >= count_max)	 // 如果计数器达到上限则返回
    		{
    			return;
    		}
    		++count;
    		f();					 // 调用function对象
    
    		// 设置定时器的终止时间为0.5秒之后
    		t.expires_at(t.expires_at() + boost::posix_time::microsec(500));
    		// 再次启动定时器,异步等待
    		t.async_wait(boost::bind(&AsynTimer::CallBack, this, boost::asio::placeholders::error));
    	}
    
    private:
    	int count;
    	int count_max;
    	boost::function<void()> f;		// function对象,持有无参无返回值的可调用物
    	boost::asio::deadline_timer t;	// asio定时器对象
    };
    
    // 第一个回调函数
    void print1()
    {
    	cout << "hello asio" << endl;
    }
    
    // 第二个回调函数
    void print2()
    {
    	cout << "hello boost" << endl;
    }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	boost::asio::io_service ios;
    
    	AsynTimer t1(ios, 10, print1); // 启动第一个定时器
    	AsynTimer t2(ios, 10, print2); // 启动第二个定时器
    
    	ios.run();	// io_service等待异步调用结束
    
    	return 0;
    }
    

    注意在async_wait()中bind的用法,CallBack是AsynTimer的一个成员函数,因此需要绑定this指针,同时还使用了asio下子名字空间placeholders下的一个占位符error,他的作业类似于bind库的占位符_1、_2,用于传递error_code值。


    接下来是AsynTimer的主要功能函数CallBack,它符合async_wait()对回调函数的要求,有一个error_code参数,当定时器终止时它将被调用执行


    CallBack函数内部累加器,如果计数器未达到上限则调用function对象f,然后重新设置定时器的终止时间,再次异步等待被调用,从而达到反复执行的目的

  • 相关阅读:
    Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
    也谈PostgreSQL的Vacuum机制及其最佳实践
    django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS
    Error: Invalid CSS after
    win32-x64-64inding.node is not a valid Win32 application
    Error: Module did not self-register
    数据分析|如何利用BI工具,探索各商品的潜在关联价值
    Python爬虫入门教程 42-100 爬取儿歌多多APP数据-手机APP爬虫部分
    Retrofit的文件上传和进度提示
    Retrofit的文件上传和进度提示
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3230970.html
Copyright © 2020-2023  润新知