Boost.Asio c++ 网络编程翻译(13)

异步工作

异步工作不仅仅指用异步地方式接受客户端到服务端的连接,异步从一个socket读取或者写入到socket。它包含了所有可以异步执行的操作。

默认情况下,你是不知道每个异步handler的调用顺序的。除了通常的异步调用(来自异步socket的读取/写入/接受)。你可以使用service.post()来使你的自定义方法被异步地调用。例如:

#include <boost/thread.hpp>

#include <boost/bind.hpp>

#include <boost/asio.hpp>

#include <iostream>

using namespace boost::asio;

io_service service;

void func(int i) {

std::cout << "func called, i= " << i << std::endl;

}

void worker_thread() {

service.run();

}

int main(int argc, char* argv[]) {

for ( int i = 0; i < 10; ++i)

service.post(boost::bind(func, i));

boost::thread_group threads;

for ( int i = 0; i < 3; ++i)

threads.create_thread(worker_thread);

// wait for all threads to be created

boost::this_thread::sleep( boost::posix_time::millisec(500));

threads.join_all();

}

在上面的例子中,service.post(some_function)添加了一个异步方法调用。 这个方法在某一个调用了service.run()的线程中请求io_service实例,然后调用给定的some_funtion之后立即返回。在我们的例子中,这个线程是我们之前创建的三个线程中的一个。你不能确定异步方法调用的顺序。你不要期待它们会以我们调用post()方法的顺序来调用。下面是运行之前代码可能得到的结果:

func called, i= 0

func called, i= 2

func called, i= 1

func called, i= 4

func called, i= 3

func called, i= 6

func called, i= 7

func called, i= 8

func called, i= 5

func called, i= 9

有时候你会想让一些异步处理方法顺序执行。比如,你去一个餐馆(go_to_restaurant),下单(order),然后吃(eat)。你需要先去餐馆,然后下单,最后吃。这样的话,你需要用到io_service::strand,这个方法会让你的异步方法被顺序调用。看下面的例子:

using namespace boost::asio;

io_service service;

void func(int i) {

std::cout << "func called, i= " << i << "/"

<< boost::this_thread::get_id() << std::endl;

}

void worker_thread() {

service.run();

}

int main(int argc, char* argv[])

{

io_service::strand strand_one(service), strand_two(service);

for ( int i = 0; i < 5; ++i)

service.post( strand_one.wrap( boost::bind(func, i)));

for ( int i = 5; i < 10; ++i)

service.post( strand_two.wrap( boost::bind(func, i)));

boost::thread_group threads;

for ( int i = 0; i < 3; ++i)

threads.create_thread(worker_thread);

// wait for all threads to be created

boost::this_thread::sleep( boost::posix_time::millisec(500));

threads.join_all();

}

在上述代码中,我们保证前面的5个线程和后面的5个线程是顺序执行的。func called, i = 0在func called, i = 1之前被调用,然后调用func called, i = 2……同样func  called, i = 5在func called, i = 6之前,func called, i = 6在func called, i = 7被调用……你需要注意尽管方法是顺序调用的,但是不意味着它们都在同一个线程执行。运行这个程序可能得到的一个结果如下:

func called, i= 0/002A60C8

func called, i= 5/002A6138

func called, i= 6/002A6530

func called, i= 1/002A6138

func called, i= 7/002A6530

func called, i= 2/002A6138

func called, i= 8/002A6530

func called, i= 3/002A6138

func called, i= 9/002A6530

func called, i= 4/002A6138

Asynchronous post() VS dispatch() VS wrap()

Boost.Asio提供了三种让你把处理方法添加为异步调用的方式:

service.post(handler):这个方法能确保其在请求io_service实例调用了指定的处理方法之后立即返回。handler稍后会在某个调用了service.run()的线程中被调用。

service.dispatch(handler):这个方法请求io_service实例去调用给定的处理方法,但是另外,如果当前的线程调用了service.run(),它可以在方法中直接调用handler。

service.wrap(handler):这个方法创建了一个包装方法,当调用它时会调用service.dispatch(handler),这个会让人有点困惑,接下来我会简单的解释它是什么意思。

在之前的章节中你会看到关于service.post()的一个例子,以及运行这个例子可能的得到的一种结果。我们对它做一些修改,然后看看service.

dispatch()是怎么影响输出的结果的:

using namespace boost::asio;

io_service service;

void func(int i) {

std::cout << "func called, i= " << i << std::endl;

}

void run_dispatch_and_post() {

for ( int i = 0; i < 10; i += 2) {

service.dispatch(boost::bind(func, i));

service.post(boost::bind(func, i + 1));

}

}

int main(int argc, char* argv[]) {

service.post(run_dispatch_and_post);

service.run();

}

在解释发生了什么之前,我们运行程序,观察结果:

func called, i= 0

func called, i= 2

func called, i= 4

func called, i= 6

func called, i= 8

func called, i= 1

func called, i= 3

func called, i= 5

func called, i= 7

func called, i= 9

偶数先输出,然后是奇数。这是因为我用dispatch()输出偶数,然后post()输出奇数。dispatch()会在返回之前调用hanlder,因为当前的线程调用了service.run(),而post()每次都立即返回了。

现在,让我们讲讲service.wrap(handler)。wrap()返回了一个仿函数,它可以用作另外一个方法的参数:

using namespace boost::asio;

io_service service;

void dispatched_func_1() {

std::cout << "dispatched 1" << std::endl;

}

void dispatched_func_2() {

std::cout << "dispatched 2" << std::endl;

}

void test(boost::function<void()> func) {

std::cout << "test" << std::endl;

service.dispatch(dispatched_func_1);

func();

}

void service_run() {

service.run();

}

int main(int argc, char* argv[]) {

test( service.wrap(dispatched_func_2));

boost::thread th(service_run);

boost::this_thread::sleep( boost::posix_time::millisec(500));

th.join();

}

test(service.wrap(dispatched_func_2));会把dispatched_ func_2包装起来创建一个仿函数,然后传递给test当作一个参数。当test()被调用时,它会分发调用方法1,然后调用func()。这时,你会发现调用func()和service.dispatch(dispatched_func_2)是等价的,因为它们是连续调用的。程序的输出如下:

test

dispatched 1

dispatched 2

时间: 2024-10-10 06:33:11

Boost.Asio c++ 网络编程翻译(13)的相关文章

Boost.Asio c++ 网络编程翻译(1)

第一次翻译,希望大家多多指正 实战出精华 Boost.Asio C++ 网络编程 用具体的C++网络编程例子来提升你的技能 John Torjan 用具体的C++网络编程例子来提升你的技能 Copyright ? 2013 Packt Publishing 版权所有,除了在鉴定文章或者评论中进行简单引用,如果没有经过出版者事先的书面授权,该书的任何部分都不能被转载.存储在检索系统中.或者以任何形式和方式传阅. 在这本书准备发行之前,我们已经尽我们最大的努力去保证书中信息的准确性.但是,这本书中包

Boost.Asio c++ 网络编程翻译(20)

异步服务端 这个图表是相当复杂的:从Boost.Asio出来你可以看到4个箭头指向on_accept,on_read,on_write和on_check_ping.着也就意味着你永远不知道哪个异步调用是下一个完成的调用,但是你可以确定的是它是这4个操作中的一个. 现在,我们是异步的了:我们可以继续保持单线程.接受客户端连接是最简单的部分,如下所示: ip::tcp::acceptor acceptor(service, ip::tcp::endpoint(ip::tcp::v4(), 8001)

Boost.Asio c++ 网络编程翻译(30)[完结]

PS:至此终于完成了Boost.Asio C++ network programming一书的翻译,这是我人生第一本完整翻译的书,从开始的磕磕绊绊,到最后小有心得,我收获很多.我将把这个系列的博客进行整理和校对,希望有兴趣的人可以帮我一起,来给大家提供更好更专业的阅读体验. 句柄追踪信息到文件 默认情况下,句柄的追踪信息被输出到标准错误流(相当于std::cerr).你想把输出重定向到其他地方的可能性是非常高的.对于控制台应用,输出和错误输出都被默认输出到相同的地方,也就是控制台.但是对于一个w

Boost.Asio c++ 网络编程翻译(14)

保持活动 假如,你需要做下面的操作: io_service service; ip::tcp::socket sock(service); char buff[512]; ... read(sock, buffer(buff)); 在这个例子中,sock和buff的存在时间都必须比read()调用的时间要长.也就是说,在调用read()返回之前,它们都必须有效.这就是你期望的:你传给一个方法的所有参数在参数内部都必须有效.当我们采用异步方式时,事情会变得越复杂. io_service servi

Boost.Asio c++ 网络编程翻译(3)

Boost.Asio入门 什么是Boost.Asio 简单来说,Boost.Asio是一个跨平台的.主要用于网络和其他一些底层输入/输出编程的C++库. 计算机网络的设计方式有很多种,但是Boost.Asio的的方式远远优于它们.它在2005年就被包含进Boost,然后被广大Bosot的用户测试并在很多项目中使用,比如Remobo(http://www.remobo.com),可以让你创建你自己的即时私有网络(IPN),libtorrent(http://www.rasterbar.com/pr

Boost.Asio c++ 网络编程翻译(11)

*_at方法 这些方法在一个流上面做随机存取操作.你来指定read和write操作从什么地方開始(offset): async_read_at(stream, offset, buffer [, completion], handler):这种方法在一个指定的流上从offset处開始运行一个异步的read操作,当操作结束时,他会调用handler. handler的格式为:void handler(const boost::system::error_code&  err, size_t byt

Boost.Asio c++ 网络编程翻译(26)

Boost.Asio-其他特性 这章我们讲了解一些Boost.Asio不那么为人所知的特性.标准的stream和streambuf对象有时候会更难用一些,但正如你所见.它们也有它们的益处.最后,你会看到姗姗来迟的Boost.Asio协程的入口,它能够让你的异步代码变的很易读.这是很惊人的一个特性. 标准stream和标准I/O buffer 读这一章节之前你须要对STL stream和STL streambuf对象有所了解. Boost.Asio在处理I/O操作时支持两种类型的buffer: b

Boost.Asio c++ 网络编程翻译(6)

io_service类 你应该已经发现大部分使用Boost.Asio编写的代码都会使用几个ios_service的实例.ios_service是这个库里面最重要的类:它负责和操作系统打交道,等待所有异步操作的结束,然后为每一个异步操作调用完成处理程序. 如果你选择用同步的方式来创建你的应用,你不需要考虑我将在这一节向你展示的东西. 你可以用几种不同的方式来使用io_service.在下面的例子中,我们有3个异步操作,2个socket连接和一个计时器等待: 有一个io_service和一个处理线程

Boost.Asio c++ 网络编程翻译(7)

Boost.Asio基本原理 这一章涵盖了你使用Boost.Asio时必须知道的一些事情.我们也将深入研究比同步编程更机警.更有乐趣的异步编程. 网络API 这一部分包含了当使用Boost.Asio编写网络应用程序时你必须知道的事情. Boost.Asio命名空间 Boost.Asio的一切都需要包含在boost::asio的命名空间或者其子命名空间内. boost::asio:这是核心类和函数所在的地方.重要的类有io_service和streambuf.类似read, read_at, re