前言
之前公司用的boost库作为底层开发库,网络方面用的asio,asio是很好用的c++异步编程库,但boost功能太多,太大,编译使用起来很麻烦。
随着c++11的诞生,代码对boost的依赖已经逐步减少,因为boost的依赖库太过庞大, boost的很多优秀的模块都已经加入到c++11,如智能指针,auto,bind,智能锁,线程等等。
asio的官网已经说明可以脱离boost独立编译了。
在windows上可以直接下载asio库,解压后,不用编译,直接加到项目中就可以使用,添加头文件
<asio.hpp>
asio 库下载地址1.13.0 (Development)
实例
在看官网例子中
Source listing for Timer.5
//
// timer.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <iostream>
#include <asio.hpp>
#include <boost/bind.hpp>
class printer
{
public:
printer(asio::io_context& io)
: strand_(asio::make_strand(io)),
timer1_(io, asio::chrono::seconds(1)),
timer2_(io, asio::chrono::seconds(1)),
count_(0)
{
timer1_.async_wait(asio::bind_executor(strand_,
boost::bind(&printer::print1, this)));
timer2_.async_wait(asio::bind_executor(strand_,
boost::bind(&printer::print2, this)));
}
~printer()
{
std::cout << "Final count is " << count_ << std::endl;
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << std::endl;
++count_;
timer1_.expires_at(timer1_.expiry() + asio::chrono::seconds(1));
timer1_.async_wait(asio::bind_executor(strand_,
boost::bind(&printer::print1, this)));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << std::endl;
++count_;
timer2_.expires_at(timer2_.expiry() + asio::chrono::seconds(1));
timer2_.async_wait(asio::bind_executor(strand_,
boost::bind(&printer::print2, this)));
}
}
private:
asio::strand<asio::io_context::executor_type> strand_;
asio::steady_timer timer1_;
asio::steady_timer timer2_;
int count_;
};
int main()
{
asio::io_context io;
printer p(io);
asio::thread t(boost::bind(&asio::io_context::run, &io));
io.run();
t.join();
return 0;
}
去掉对boost的依赖,用c++11的方法,和最新版本asio,代码如下:
#include <iostream>
#include <asio.hpp>
class printer
{
public:
printer(asio::io_context& io)
: strand_(io), //strand_(asio::make_strand(io)),
timer1_(io, asio::chrono::seconds(1)),
timer2_(io, asio::chrono::seconds(1)),
count_(0)
{
timer1_.async_wait(asio::bind_executor(strand_,
std::bind(&printer::print1, this)));
timer2_.async_wait(asio::bind_executor(strand_,
std::bind(&printer::print2, this)));
}
~printer()
{
std::cout << "Final count is " << count_ << std::endl;
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << std::endl;
++count_;
timer1_.expires_at(timer1_.expiry() + asio::chrono::seconds(1));
timer1_.async_wait(asio::bind_executor(strand_,
std::bind(&printer::print1, this)));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << std::endl;
++count_;
timer2_.expires_at(timer2_.expiry() + asio::chrono::seconds(1));
timer2_.async_wait(asio::bind_executor(strand_,
std::bind(&printer::print2, this)));
}
}
private:
//asio::strand<asio::io_context::executor_type> strand_;
asio::io_context::strand strand_;
asio::steady_timer timer1_;
asio::steady_timer timer2_;
int count_;
};
int main()
{
asio::io_context io;
printer p(io);
//asio::thread t(boost::bind(&asio::io_context::run, &io));
//asio::thread t(std::bind([&io]() {io.run(); }));
//std::thread t(std::bind([&io]() {io.run(); }));
std::thread t([&io]() {io.run(); });
io.run();
t.join();
return 0;
}
类boost::asio::io_context::strand的主要作用是在asio中利用多线程进行事件处理的时候,如果涉及到多线程访问共享资源,借助于strand类,我们不需要显示的使用线程同步相关的类(比如mutex)就可以让多个事件处理函数依次执行。
简而言之,strand定义了事件处理程序的严格顺序调用。
我们知道,若多个线程调用了同一个io_context对象的run方法,那么该对象关联的多个事件处理函数 可能就会被不同的线程同时执行(即并发执行),若这些事件处理函数访问同一个非线程安全的共享资源时,就可能会产生线程同步问题。 但是若我们将这些事件处理函数bind到同一个strand对象上,那么asio库保证在上一个事件处理函数处理完成之前是没法执行下一个事件处理函数的(相当于阻止了并发执行)。