C++异步编程方式
“Boost是一个极致漂亮的设计”——这是我在这一段时间内学习使用这个C++准标准库时不断涌现在我脑海的想法。不过话说回来,即便这样,C++那浩如烟海的技巧以及模板那毁誉参半的语法依然还是让人头痛的事情。
Boost中有说不完的漂亮设计,无论是对函数式编程方式的支持、还是异步IO的接口、正则表达式、字符串处理算法、容器,无一不是独具匠心。更不用说这个代码跨平台的兼容性很好了。感觉C++从来没有放弃其兼容并包的设计思想,“没有最好的,只有最合适的,C++提供你能想到的编程方式,你只要在需要的时候使用”。另外,C++也从其后来者(Java)身上学习经验,无论是功能完备的smart pointer还是各种容器类、IO机制、多线程支持,显然告诉别人,C++要在类库层级造一个Java虚拟机。
最近用的比较多的是Boost的Asio库,里面提供了跨平台的异步IO的支持(Linux下的epoll、win32下的IOCP)。一段时间的使用后,体会最深的异步编程方式,趁现在还没忘记,赶紧写下一些体会。所以异步,相对以前的同步编程而言。以前同步模式下,一个函数调用是阻塞的,比如,我们在代码里写:
void foo()
{
...
int a = func(); //一次函数调用
...
}
里面调用了func()函数,这次调用将会返回一个整数值,那么除非func执行完并返回结果了,否则是不会执行下一句的。这就类似于打电话,你说法的时候,我一直在这边听着,你说完就到我说。
而异步方式就不同了,就像发email,你发的时候我不一定在,等到我在的时候看到邮件,可能立刻回,也可能晚点回,你也不需要一直开着邮箱才能收到。如果是程序设计可能是这样:
void callback(int result)
{
// 处理结果数据
}
void foo()
{
func(callback);
}
调用func的时候,可能还没有得到答案。知道func返回后的某一个时间,callback才被调用,这个时候,才得到结果。这个和以前Windows里面的回调函数又有些不同。win32 API,不如像EnumWindows,事实上是同步的,传进去的回调会在EnumWindows返回之前被执行。而异步模式下,callback函数什么时候被执行是不确定的,可能要在func返回以后很久。
明白了这个以后,就有一个问题了,如果调用有状态怎么办?也就是说,每次调用func的时候,程序的执行状态可能不一样,我们需要callback能够根据这些状态来选择执行不同的功能。
Boost里面提供了函数对象(用boost::bind和boost::function库)。其思想类似于传一个callback对象,类似于将带有参数拷贝的函数指针传到异步函数里面去,比如:
TCallBack {
type1 param1;
type2 param2;
void (*callback_function)(type1,type2);
}
那么func就接收一个TCallBack类型的函数,那么调用的时候,类似于:
*(obj.callback_function)(obj.param1, obj.param2)
通过C++的模板机制,可是不显式地声明TCallBack类型。而只要通过bind就能产生这样一个对象。