首页 > 代码库 > Boost.Asio c++ 网络编程翻译(13)

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


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