boost asio read的asio异步调用的疑问,该怎么解决

Linux(7)
& & & &本节深入讨论异步编程将遇到的若干问题。建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的。
为什么需要异步
& & & &如前所述,通常同步编程要比异步编程更简单。同步编程下,我们很容易线性地对问题进行考量,函数A调用完,继续执行B,B执行完,继续执行C,以此类推,相对比较直观。而对于异步编程,假设有5个事件,我们很难知道它们具体的执行顺序,你甚至不知道,它到底会不会被执行。
虽然编写异步的程序,很难,但是依然需要使用这种方法。因为服务器程序需要同时并行的处理大量的客户端。并行的客户端越多,异步编程的优势就越明显。
& & & & 假设有一个服务器程序,需要同时处理1000个并行的客户端,客户端和服务器之间的通信消息,以’\n’来结尾。
这是同步模式下的代码,使用1个线程:
using namespace boost::
struct client{
char buff[1024];
int already_
std::vector&client&
void handle_clients() {
while(true) {
for(int i=0; i&clients.size(); ++i) {
if(clients[i].sock.available() ) on_read(clients[i]));
void on_read(client& c) {
int to_read = std::min(1024 - c.already_read, c.sock.available());
c.sock.read_some(buffer(c.buff + c.already_read, to_read);
c.already_read += to_
if(std::find(c.buff, c.buff + c.already_read, '\n') & c.buff + c.already_read) {
int pos = std::find(c.buff, c.buff + c.alread_read, '\n') - c.
std::string msg(c.buff, c.buff + pos);
std::copy(c.buff + pos, c.buff + 1024, c.buff);
c.already_read -=
on_read_msg(c, msg);
void on_read_msg(client & c, const std::string& msg) {
if(msg == "request_login")
c.sock.write("request_ok\n");
else if ...
&&&& 在任务服务器程序中,你都需要避免代码被阻塞。看上面的代码,我们希望handle_clients()这个函数尽可能的不被阻塞。任何时候函数阻塞,从客户端发来的消息就会等待,直到函数不阻塞的时候才能来处理它们。为了避免程序被阻塞,我们只在socket中确实有数据的时候才去读取,实现的代码是:
if(clients[i].sock.available() ) on_read(clients[i]));
在on_read函数中,我们只读取socket确实有效的数据;调用read_util(c.sock, buffer(…),’\n’);是非常不好的选择,它会阻塞程序,直到完整的读取了全部的数据才返回。我们永远不知道到底什么时候才能读取完毕。
&&&& 程序的瓶颈是on_read_msg()这个函数;所有输入的数据都被卡在这里。on_read_msg()应该尽量避免出现这种情况,但有时这又是完全没办法避免的。(比如,当socket的缓冲区满了以后,操作必将被阻塞)。
&&&& 下面是同步模式下的代码,使用10个线程:
using namespace boost::
bool set_reading() {
boost::mutex::scope_lock lk(cs_);
if(is_reading_) return false;
else { if_reading_ = true; return true; }
void unset_reading() {
boost::mutex::scoped_lock lk(cs_);
is_reading_ = false;
boost::mutex cs_;
bool is_reading_;
std::vector&client&
void handle_clients() {
for(int i=0; i&10; ++i) {
boost::thread(handle_clients_thread);
void handle_clients_thread() {
while(true) {
for(int i=0; i&clients.size(); ++i) {
if(clients[i].sock.available()) {
if(clients[i].set_reading()) {
on_read(clients[i]);
clients[i].unset_reading();
void on_read(client & c) {
void on_read_msg(client & c, const std::string& msg) {
&&&& 为了使用多线程,我们需要同步机制,set_reading()和unset_reading()就是在做这个用的。set_reading(),非常重要,它测试当前是否有线程在做读取操作。
&&&& 可以看出来代码已经比较复杂了。
&&&& 还有一种同步编程的方法,就是每个client分配一个线程。但是随着并行的客户端数量的增长,这显然是不可行的。
&&&& 现在我们来看看异步方法。当client请求数据的时候,on_read被调用,发送返回数据,之后又等待下一个请求(执行另一个异步的读操作)。
异步代码,10个线程:
using namespace boost::
struct client {
std::vector&client&
void handle_clients() {
for(int i=0; i&clients.size(); ++i) {
async_read_util(clients[i].sock, clients[i].buff, '\n',
boost::bind(on_read, clients[i], _1, _2));
for(int i=0; i&10; ++i)
boost::thread(handle_clients_thread);
void handle_clients_thread() {
service_run();
void on_read(client& c, const error_code& err, size_t read_bytes) {
std::istream in(&c.buff);
std::string
std::getline(in, msg);
if(msg == "request_login")
c.sock.async_write("request_ok\n", on_write);
else if ...
async_read_util(c.sock, c.buff, '\n',
boost::bind(on_read, c, _1, _2));
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:178696次
积分:2565
积分:2565
排名:第14539名
原创:65篇
评论:173条
(2)(2)(1)(1)(3)(1)(1)(1)(8)(1)(3)(1)(4)(3)(2)(1)(1)(2)(1)(1)(1)(2)(1)(1)(1)(1)(1)(2)(7)(5)(2)(1)(2)您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
boostasio基础资料.pdf 92页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
需要金币:350 &&
你可能关注的文档:
··········
··········
Boost.Asio C++ 网络编程
第一章 Boost.Asio入门
第二章 Boost.Asio基本原理
第三章 回显服务端/客户端
第四章 客户端和服务端
第五章 同步VS异步
第六章 Boost.Asio-其他特性
第七章 Boost.Asio-进阶
Boost.Asio C++ 网络编程
实战出精华
在具体的C++网络编程中提升你的逼格
John Torjo
Boost.Asio C++ 网络编程
Copyright (C) 2013 Packt Publishing
做为权威的C++专家,除了偶尔用C#和Java写程序,John Torjo把他超过15年编程生涯中的大部分时间都
贡献给了C++。
他也很喜欢在C++ Users Journal和其他杂志上写一些编程相关的文章。
闲暇的时候,他喜欢玩扑克、开快车。他有很多个自由职业,其中一个就把他的两个爱好结合在一起,一
个是玩扑克,另外一个是编程。如果你想联系他,可以发邮件到。
我要感谢我的朋友Alexandru Chis, Aurelian Hale, Bela Tibor Bartha, Cristian Fatu, Horia Uifaleanu,
Nicolae Ghimbovschi以及Ovidiu Deac。感谢他们对本书提出的反馈和意见。同时我也要感谢Packt公司各
位对我频繁错过截稿日期行为的包容。然后最需要感谢的是Chris Kohlhoff,Boost.Asio的作者,是他写出
了如此伟大的库。
把这本书献给我最好的朋友Darius。
关于评审员
Béla Tibor Bartha
一个使用过多种技术和语言进行开发的专业软件工程师。尽管在过去的4年里,他做的是iOS和OSX应用开
发,但是C++陪伴他度过了早期个人游戏项目开发的激情岁月。
我要感谢John,因为他我才能做这本书的评审
Nicolae Ghimbovschi
一个参加各类C++项目超过5年的天才个人开发者。他主要参与一些企业通信工程的项目。作为一个狂热的
Linux爱好者,他喜欢利用不同的操作系统、脚本工具和编程语言进行测试和实验。除了编程,他还喜欢骑
自行车、瑜伽和冥想。
Boost.Asio C++ 网络编程
我要感谢John让我来评审这本书
非主流程序猿mmoaay,技术很烂,喜欢平面设计、鼠绘、交友、运动和翻译,但是确作为一只程序猿混
迹在IT行业。热爱开源,技术烂就只好做做设计和翻译的工作。
微博 :/smmoaay
关于avplayer
中国第一技术社区。
第一章 :Boost.Asio入门
什么是Boost.Asio?
编译 Boost.Asio
同步VS异步
异常VS错误代码
Boost.Asio中的多线程
不仅仅是网络
io_service类
第二章 :Boost.Asio基本原理
Boost.Asio命名空间
同步错误代码
Socket成员函数
其他注意事项
正在加载中,请稍后...随笔 - 699&
文章 - 8&评论 - 861&trackbacks - 19
io_service对象是asio框架中的调度器,所有异步io事件都是通过它来分发处理的(io对象的构造函数中都需要传入一个io_service对象)。
asio::io_service io_
asio::ip::tcp::socket socket(io_service);
在asio框架中,同步的io主要流程如下:
应用程序调用IO对象成员函数执行IO操作
IO对象向io_service 提出请求.
io_service 调用操作系统的功能执行连接操作.
操作系统向io_service 返回执行结果.
io_service将错误的操作结果翻译为boost::system::error_code类型,再传递给IO对象.
如果操作失败,IO对象抛出boost::system::system_error类型的异常.
而异步IO的处理流程则有些不同:
应用程序调用IO对象成员函数执行IO操作
IO对象请求io_service的服务
io_service 通知操作系统其需要开始一个异步连接.
操作系统指示连接操作完成, io_service从队列中获取操作结果
应用程序必须调用io_service::run()以便于接收结果
调用io_service::run()后,io_service返回一个操作结果,并将其翻译为error_code,传递到事件回调函数中
io_service对象
io_service对象主要有两个方法——post和run:
post用于发布io事件,如timer,socket读写等,一般由asio框架相应对象调用,无需我们显式调用。
run用于监听io事件响应,并执行响应回调,对于异步io操作需要在代码中显式调用,对于同步io操作则由io对象隐式调用(并不是run函数,不过也是等待io事件)。
可见,io_service提供的是一个生产者消费者模型。在异步io操作中需要我们手动控制消费者,调用run函数,它的基本工作模式如下:
等待io事件响应,如果所有io事件响应完成则退出
等待到io事件响应后,执行其对应的回调
继续等待下一个io事件,重复1-2
从中可以看出,io_service是一个工作队列的模型。在使用过程中一般有如下几个需要注意的地方:
1. run函数在io事件完成后会退出,导致后续基于该对象的异步io任务无法执行
由于io_service并不会主动常见调度线程,需要我们手动分配,常见的方式是给其分配一个线程,然后执行run函数。但run函数在io事件完成后会退出,线程会终止,后续基于该对象的异步io任务无法得到调度。
解决这个问题的方法是通过一个asio::io_service::work对象来守护io_service。这样,即使所有io任务都执行完成,也不会退出,继续等待新的io任务。
boost::asio::io_service
boost::asio::io_service::work work(io);
2. 回调在run函数的线程中同步执行,当回调处理时间较长时阻塞后续io响应
解决这个问题的方法有两种:1. 启动多线程执行run函数(run函数是线程安全的),2. 新启动一个线程(或通过线程池)来执行回调函数。一般来讲,如果回调处理事件不是特别短,应该使用在线程池中处理回调的方式。
3. 回调在run函数的线程中同步执行,io事件较多的时候得不到及时响应
这个其实是性能问题了,在多核cpu上可以通过在多个线程中执行run函数来解决这一问题。这种方式也只能充分利用cpu性能,本身性能问题就不是光靠软件就能解决的。
.net中的异步io调度方式
和io_service这种手动控制的方式比起来,.net则是纯粹的自动档了。IO调度由CLR托管了,无需手动控制。回调也是在线程池中执行,无需担心影响后续IO响应。
正是由于CLR的托管,在.net 的异步IO框架中,就没有类似io_service的调度对象存在,这也符合.net的一贯简洁做法。
阅读(...) 评论()(原创)如何使用boost.asio写一个简单的通信程序(一) - qicosmos(江南) - 博客园
随笔 - 93, 文章 - 0, 评论 - 473, 引用 - 0
  boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介绍如何写一个简单的通信程序来告诉读者如何使用asio,希望对asio的初学者有所帮助。由于只是介绍其基本用法,作为例子的简单示例并不考虑很多的业务逻辑和异常处理,只是介绍基本用法,让初学者入门。
  使用asio容易出错的一个主要原因是因为它是基于proactor模式实现的,asio有很多异步操作接口,这些异步接口稍不注意就会出现莫名奇妙的错误,所以要用好asio的第一步是理解其异步操思想。
异步操作思想
  用户发起异步事件,asio将这些异步事件投递到一个队列中,用户发起的操作就返回了,io_service::run会处理异步事件队列中的所有的异步事件,它会将这些事件交给操作系统处理,操作系统处理完成之后会丢到asio的事件完成的队列中,io_service发现有完成队列中有完成事件了,就会通知用户处理完成事件。 所以用户要发起一个异步操作需要做三件事:
调用asio异步操作接口,发起异步操作;如:async_connect、async_read、async_write,这些异步接口需要一个回调函数入参,这个回调函数在事件完成时,由io_service触发。
调用io_service::run处理异步事件;发起一个异步操作,必须要保证io_service::run,因为io_service通过一个循环去处理这些异步操作事件的,如果没有事件就会退出,所以要保证异步事件发起之后,io_service::run还在运行。要保证一直run的一个简单办法就是使用io_service::work,它可以保证io_service一直run。
处理异步操作完成事件;在调用异步接口时会传入一个回调函数,这个回调函数就是处理操作完成事件的,比如读完成了,用户需要对这些数据进行业务逻辑的处理。
  下图描述了一个异步操作的过程:
  asio的的核心是io_service, 理解了asio异步接口的机制就容易找出使用asio过程中出现的问题了,在这里把一些常见的问题列出来,并分析原因和提出解决方法。
问题1:为什么我发起了异步操作,如连接或者写,对方都没有反应,好像没有收到连接请求或者没有收到数据? 答案:一个很可能的原因是io_service在异步操作发起之后没有run,解决办法是保持io_service run。
问题2:为什么发送数据会报错? 答案:一个可能的原因是发送的数据失效了,异步发送要求发送的数据在回调完成之前都有效,异步操作只是将异步事件句柄投递到io_service队列中就返回了,并不是阻塞的,不注意这一点,如果是临时变量的数据,出了作用域就失效了,导致异步事件还没完成时数据就失效了。解决办法,保证发送数据在事件完成之前一直有效。
问题3:为什么监听socket时,会报&函数不正确&的异常? 答案:因为监听时,也要保证这个socket一直有效,如果是一个临时变量socket,在调用异步监听后超出作用域就失效了,解决办法,将监听的socket保存起来,使它的生命周期和acceptor一样长。
问题4:为什么连续调用异步操作时会报错? 答案:因为异步操作必须保证当前异步操作完成之后再发起下一次异步操作。解决办法:在异步完成事件处理完成之后再发起新的异步操作即可。
问题5:为什么对方半天收不到数据,过了半天才一下子收到之前发送的数据? 答案:因为socket是流数据,一次发送多少数据不是外界能控制的,这也是所谓的粘包问题。解决办法,可以在接收时指定至少收多少的条件,或者做tcp分包处理。
  说了这么多,还是来看看例子吧,一个简单的通信程序:服务端监听某个端口,允许多个客户端连接上来,服务器将客户端发来的数据打印出来。 先看看服务端的需求,需求很简单,第一,要求能接收多个客户端;第二,要求把收到的数据打印出来。
  要求能接收多个客户端是第一个要解决的问题,异步接收需要用到acceptor::async_accept,它接收一个socket和一个完成事件的回调函数。前面的问题3中提到监听的这个socket不能是临时变量,我们要把它保存起来,最好是统一管理起来。可以考虑用一个map去管理它们,每次一个新连接过来时,服务器自动分配一个连接号给这个连接,以方便管理。然而,socket是不允许拷贝的,所以不能直接将socket放入容器中,还需要外面包装一层才可以。
  第二个问题是打印来自客户端的数据,既然要打印就需要异步读数据了。异步读是由socket完成,这个socket还要完成读写功能,为了简化用户操作,我将socket封装到一个读写事件处理器中,这个事件处理器只具备具备读和写的功能。服务器每次监听的时候我都会创建一个新的事件处理器并放到一个map中,客户端成功连接后就由这个事件处理器去处理各种读写事件了。 根据问题1,异步读写时要保证数据的有效性,这里我将一个固定大小的缓冲区作为读缓冲区。为了简单起见我使用同步发送,异步接收。
具体看看这个读写事件处理器是怎么写的:
const int MAX_IP_PACK_SIZE = 65536;
const int HEAD_LEN = 4;
class RWHandler
RWHandler(io_service& ios) : m_sock(ios)
~RWHandler()
void HandleRead()
//三种情况下会返回:1.缓冲区满;2.transfer_at_least为真(收到特定数量字节即返回);3.有错误发生
async_read(m_sock, buffer(m_buff), transfer_at_least(HEAD_LEN), [this](const boost::system::error_code& ec, size_t size)
if (ec != nullptr)
HandleError(ec);
cout && m_buff.data() + HEAD_LEN &&
HandleRead();
void HandleWrite(char* data, int len)
boost::system::error_
write(m_sock, buffer(data, len), ec);
if (ec != nullptr)
HandleError(ec);
tcp::socket& GetSocket()
void CloseSocket()
boost::system::error_
m_sock.shutdown(tcp::socket::shutdown_send, ec);
m_sock.close(ec);
void SetConnId(int connId)
m_connId = connId;
int GetConnId() const
return m_connId;
template&typename F&
void SetCallBackError(F f)
m_callbackError =
void HandleError(const boost::system::error_code& ec)
CloseSocket();
cout && ec.message() &&
if (m_callbackError)
m_callbackError(m_connId);
tcp::socket m_
std::array&char, MAX_IP_PACK_SIZE& m_
int m_connId;
std::function&void(int)& m_callbackE
  这个读写事件处理器有四个成员变量,第一个是socket它是具体的读写执行者;第二个是固定长度的读缓冲区,用来读数据;第三个是连接id,由连接管理层分配;第四个是回调函数,读写发生错误时回调到上层。当然还可以加一个tcp分包之后的回调函数,将应用层数据回调到应用层,这里简单起见,只是将其打印出来。
再来看看Server是如何写的:
#include &boost/asio/buffer.hpp&
#include &boost/unordered_map.hpp&
#include "Message.hpp"
#include "RWHandler.hpp"
const int MaxConnectionNum = 65536;
const int MaxRecvSize = 65536;
class Server
Server(io_service& ios, short port) : m_ios(ios), m_acceptor(ios, tcp::endpoint(tcp::v4(), port)), m_cnnIdPool(MaxConnectionNum)
int current = 0;
std::generate_n(m_cnnIdPool.begin(), MaxConnectionNum, [&current]{return ++ });
void Accept()
cout && "Start Listening " &&
std::shared_ptr&RWHandler& handler = CreateHandler();
m_acceptor.async_accept(handler-&GetSocket(), [this, handler](const boost::system::error_code& error)
if (error)
cout && error.value() && " " && error.message() &&
HandleAcpError(handler, error);
m_handlers.insert(std::make_pair(handler-&GetConnId(), handler));
cout && "current connect count: " && m_handlers.size() &&
handler-&HandleRead();
void HandleAcpError(std::shared_ptr &RWHandler& eventHanlder, const boost::system::error_code& error)
cout && "Error,error reason:" && error.value() && error.message() &&
//关闭socket,移除读事件处理器
eventHanlder-&CloseSocket();
StopAccept();
void StopAccept()
boost::system::error_
m_acceptor.cancel(ec);
m_acceptor.close(ec);
m_ios.stop();
std::shared_ptr&RWHandler& CreateHandler()
int connId = m_cnnIdPool.front();
m_cnnIdPool.pop_front();
std::shared_ptr&RWHandler& handler = std::make_shared&RWHandler&(m_ios);
handler-&SetConnId(connId);
handler-&SetCallBackError([this](int connId)
RecyclConnid(connId);
void RecyclConnid(int connId)
auto it = m_handlers.find(connId);
if (it != m_handlers.end())
m_handlers.erase(it);
cout && "current connect count: " && m_handlers.size() &&
m_cnnIdPool.push_back(connId);
io_service& m_
tcp::acceptor m_
boost::unordered_map&int, std::shared_ptr&RWHandler&& m_
list&int& m_cnnIdP
这个Server具备连接管理功能,会统一管理所有连上来的客户端。 其中的Message类是boost官网中的那个
class Message
enum { header_length = 4 };
enum { max_body_length = 512 };
: body_length_(0)
const char* data() const
return data_;
char* data()
return data_;
size_t length() const
return header_length + body_length_;
const char* body() const
return data_ + header_
char* body()
return data_ + header_
size_t body_length() const
return body_length_;
void body_length(size_t new_length)
body_length_ = new_
if (body_length_ & max_body_length)
body_length_ = max_body_
bool decode_header()
char header[header_length + 1] = "";
std::strncat(header, data_, header_length);
body_length_ = std::atoi(header);
if (body_length_ & max_body_length)
body_length_ = 0;
return false;
return true;
void encode_header()
char header[header_length + 1] = "";
std::sprintf(header, "%4d", body_length_);
std::memcpy(data_, header, header_length);
char data_[header_length + max_body_length];
std::size_t body_length_;
  至此一个简单的服务端程序写完了,还要把这个Server运行起来。
void TestServer()
//boost::asio::io_service::work work(ios);
//std::thread thd([&ios]{ios.run(); });
Server server(ios, 9900);
server.Accept();
ios.run();
//thd.join();
注意看这个TestServer函数,看我是如何保证io_service::run一直运行的, 我这里没有使用io_service::work来保证,用了一种更简单的方法,具体方法读者看代码便知。
现在可以写一个简单的客户端来测试一下,看看服务器能否正常工作,下一篇再继续写如何写一个简单的客户端程序。
如果你觉得这篇文章对你有用,可以点一下推荐,谢谢。
c++11 boost技术交流群:,欢迎大家来交流技术。boost.asio问题,看到的例子,不理解,求大婶解释下!【c++吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:290,243贴子:
boost.asio问题,看到的例子,不理解,求大婶解释下!收藏
#include &iostream&#include &boost\asio.hpp&#include &boost\bind.hpp&#include &boost\date_time\posix_time\posix_time.hpp&#include &boost/thread.hpp& class printer{public: printer(boost::asio::io_service& io):strand_(io),
timer1(io,boost::posix_time::seconds(1)),
timer2(io,boost::posix_time::seconds(1)),
count(0) {
timer1.async_wait(strand_.wrap(boost::bind(&printer::print1,this)));
timer2.async_wait(strand_.wrap(boost::bind(&printer::print2,this))); } ~printer() {
std::cout&&"结果"&&count&&std:: } void print1() {
if(count&10)
std::cout&&"定时器1 "&&count&&std::
timer1.expires_at(timer1.expires_at()+boost::posix_time::seconds(1));
timer1.async_wait(strand_.wrap(boost::bind(&printer::print1,this)));
} } void print2() {
if(count&10)
std::cout&&"定时器2 "&&count&&std::
timer2.expires_at(timer2.expires_at()+boost::posix_time::seconds(1));
timer2.async_wait(strand_.wrap(boost::bind(&printer::print2,this)));
} }private: boost::asio::strand strand_; boost::asio::deadline_timer timer1; boost::asio::deadline_timer timer2;}; int main(){ boost::asio::io_ printer p(io); boost::thread t(boost::bind(&boost::asio::io_service::run,&io)); io.run(); t.join(); //system("pause"); return 0;}不知道它是怎么实现每个定时器一次轮回回调的?
原文地址:
帖子都沉了,都没人理我啊!这么伤人啊!!!
再顶上去一次,求大婶了
别找我boost神马的只用过python和multi_array
雾导帝,不带这么欺负新人的啊!!!!你帮我问问吧,吧里熟一点的ID就上面几个了!
高中生而已....表示这些玩意如果要弄的话我会去boost.org...不过现在看一本450页的英文小说中(上课要用的)限时3~4周...
我英语现在一级的水平可能都缺,去boost.org,我差不多拿着有道词典一句句的翻译,可是一些专业词汇,有道完全乱套了,导致完全看不懂那个!这个是我在仅有的一些中文资料中找到的例子,不理解,才上来找帮助的,高中,我还不知道C++为何物!
boost 从来不用所以换人。
大婶,帮我召唤几个吧,七级新人只熟悉你们这几个ID
帖子又要沉了,求指点,求大婶!
每个定时器一次轮回回调意思我没太懂,我理解这个例子就是,定时器到期后调用句柄函数,句柄函数修改定时器到期的时间,然后在重新启用定时器
我也是刚刚开始学习boost,如果有兴趣的话可以加我的
看了一下,printer构造后,两个timer都在异步等着,1s后回调printX(),输出信息,把timerX延时1s继续异步等,直到count_到10。两线程处于竞争状态,由于总是同时结束等待,调用次序不确定,但由strand_保证不会被同时调用(避免数据、资源竞争)
前面一段看的我有点纠结了,您来这个不一定对,让我瞬间凋谢了!
飞翔,再给俺整清楚点吧,这个问题纠结几天了!
就是你说的这个,两线程处于竞争状态是怎么实现的?然后我试验了很多遍,调用次序是确定的,先timer2然后timer1,再timer2这样依次调用,累计输出10结束!主要就是这个定时器依次调用是怎么弄,我没弄懂!新人求解!
你不会没看到我的回复吧!飞翔大婶?????
你试验了很多遍
我真试验了很多遍,最少七八遍,都是先timer2!呃,这种极低概率的事被我碰上了么?
才看到这个,不过我很少上QQ了,就不加了,加了也算是浪费了!
飞翔大婶,我再次运行了十遍,全部都是先timer2先调用,然后timer1调用,再然后timer2调用……共十次,我试了清理解决方案,重新生成解决方案,甚至重建了三个项目试验都是样,请问这是怎么回事?
这就不知道了
难道是传说中的人品
飞翔大婶 我给你选七个号
你去买彩票吧 中了五百万记得分我十块二十块的
登录百度帐号推荐应用

我要回帖

更多关于 boost asio 中文教程 的文章

 

随机推荐