http://hi.baidu.com/maple0015/blog/item/7a11ed50f39a4f65853524ee.html
在写程序的过程中,我们可能会需要对某些功能实现异步操作,比如记录调用日志等。
提到异步,我们最容易想到的就是多线程:我们可以启动另外一个线程,把一部分工作交给另外一个线程去执行,而当前线程继续去做一些更加急迫的事情。这里的“把一部分工作交给另外一个线程取执行”,是通过将要执行的函数的函数入口地址告诉另外一个线程来实现的,当新的线程有了函数的入口地址,就可以调用该函数。
我们先来看一下怎样使用C#中的Thread类来实现异步。
在C#中,Thread类是常用的用来启动线程的类:
实际上,这里创建的ThreadStart对象,封装的就是方法“myStartingMethod”的入口地址。C#中通过Delegate对象,可以方便的封装函数入口地址。
而Delegate,实际上是用来描述函数定义的,比如上面提到的ThreadStart委托,他的声明如下:
这句话声明了一个叫做ThreadStart的委托类型,而且该声明表示:ThredStart这个委托类型,只能封装“返回值为void、没有参数”的函数的入口地址。如果我们给ThreadStart类的构造函数传递的方法不符合,则会出错:
实际上,我们在使用多线程时,要异步执行的函数往往会有一些参数。比如记录日志时,我们需要告诉另外一个线程日志的信息。
因此,Thread类除了接受ThreadStart委托,还接受另外一个带参数的委托类型ParameterizedThreadStart:
ParameterizedThreadStart 委托可以用来封装返回值为void、具有一个object类型参数的函数。这样,我们就可以往另外一个函数中传递参数了——只不过,如果要传递多个参数,我们必须将参数封装一下,弄到一个object对象中去。比如下面的例子中,本来我们需要传递两个整数的,但为了符合ParameterizedThreadStart的声明,我们需要改造一下函数:
ParameterizedThreadStart委托必须与Thread.Start(Object) 方法一起使用——委托只是用来传递函数入口,但函数的参数是通过Thread.Start方法传递的。
另外需要注意的,从这里我们可以看到,这样的使用方法并不是类型安全的,我们无法保证myStartingMethod方法的参数threadData永远都是MyStartingMethodParameterWarpper 类型,因此我们还需要加上判断;另外这样实际上也加大了程序间的沟通成本:如果有人需要异步执行myStartingMethod方法,那么他就必须知道其参数的实际类型并保证参数传递正确,而这块编译器已经无法通过编译错误的方式通知你了。
.