异步委托
创建线程的一个简单的方式就是定义一个委托进行异步调用,异步调用委托的方式有三种:投票、等待句柄和异步回调。
.投票
通过IAsynResult的IsCompleted方法判断异步操作是否完成
public delegate int TakesAWhileDelegate(int data, int ms);
private static int TakesAWhile(int data, int ms) {//50ms暂停期间执行
Console.WriteLine("Takeswhile started");
Thread.Sleep(ms);
Console.WriteLine("Takeswhile compeleted");
return ++data;
}
static void Main(string[] args)
{
TakesAWhileDelegate dl = TakesAWhile;//委托
IAsyncResult ar = dl.BeginInvoke(1, 3000, null, null);
while (!ar.IsCompleted) {//委托函数执行完成后返回true
Console.Write(".");//先执行
Thread.Sleep(50);
}
int result = dl.EndInvoke(ar);
Console.WriteLine("result:{0}", result);
Console.ReadLine();
}
结果:
等待句柄
等待异步委托的结果的另一种方式是使用与IAsyncResult相关联的等待句柄。使用AsyncWaitHandle属性可以访问等待句柄。。这个属性返回一个WaitHandle类型的对象,它可以等待委托线程完成其任务。而WaitOne()方法将一个超时时间作为可选的第一个参数,在其中可以定义要等待的最长时间。这里设置为5毫秒。如果发生超时,**WaitOne()**方法就返回false,While循环会继续执行。如果等待操作成功,就用一个中断退出循环,用委托的EndInvoke()方法接收结果。从UI的立场来看,结果与前面的示例类似,只是用另一种方式执行等待操作。
IAsyncResult ar = dl.BeginInvoke(1, 6000, null, null);
while (true)
{
Console.Write(".");
if (ar.AsyncWaitHandle.WaitOne(5, false))//等待5ms如果没结束返回false
{
Console.WriteLine("Can get the result now");
break;
}
}
int result = dl.EndInvoke(ar);
Console.WriteLine("result:{0}", result);
如果将6000变为2ms,立马就能退出循环
异步回调
等待委托的结果的第3种方式是使用异步回调。在BeginInvoke()方法的第3个参数中,可以传递一个满足AsyncCallback委托的需求的方法。AsyncCallback委托定义了一个IAsyncResult类型的参数,其返回类型是void。这里,把TakesAWhileCompleted()方法的地址赋予第3个参数,它满足AsyncCallback委托的需求。对于最后一个参数,可以传递任意对象,以便从回调方法中访问它。传递委托实例很有用,这样回调方法就可以使用它获得异步方法的结果。现在,只要TakesAWhileDelegate委托完成其任务,就调用TakesAWhileCompleted方法。不需要在主线程中等待结果。但是在委托线程的任务未完成之前,不能停止主线程,除非主线程结束时停止的委托线程没有问题。
dl.BeginInvoke(1, 3000, TakesAWhileCompeleted, dl);
private static void TakesAWhileCompeleted(IAsyncResult ar)
{
TakesAWhileDelegate dl = ar.AsyncState as TakesAWhileDelegate;
int result = dl.EndInvoke(ar);
Console.WriteLine("result:{0}", result);
}
//lamda表达式
dl.BeginInvoke(1,3000,ar=>{
int result = dl.EndInvoke(ar);
},null)
Thread类
使用Thread类控制和创建线程。Thread类构造函数重载为接收ThreadStart和ParameterizedThreadStart类型的委托参数.
只要有一个前台线程在运行,应用程序的进程就在运行。如果多个前台线程在运行,而main()
方法结束了,应用程序的进程就仍然是激活的,直到所有前台线程完成其任务为止。
在默认情况下,用Thread类创建的线程是前台线程。线程池中的线程总是后台线程。
var ti = new Thread(ThreadMain);
t1.start();
static void ThreadMain(){
..........
}
给线程传递数据
给线程传递数据的两种方式:1.parameterizedThreadStart委托参数的Thread构造函数。2.自定义类
static void Main(string[] args)
{
var d = new Data { Message = "Info" };
var t2 = new Thread(ThreadPara);
t2.Start(d);
Console.ReadLine();
}
public struct Data {
public string Message;
}
static void ThreadPara(object o) {
Data d = (Data)o;
Console.WriteLine("Running in a thread,received{0}", d.Message);
}
第二种传递参数的方式是通过类
public class Mythread
{
private string data;
public Mythread(string data) {
this.data = data;
}
public void ThreadMain()
{
Console.WriteLine("Running in a thread:{0}", data);
}
}
var obj = new Mythread("info");
var t3 = new Thread(obj.ThreadMain);
t3.start();
可以通过控制isbackground参数控制线程是前台线程还是后台线程。当Main程序结束,前台线程也不会结束。
static void ThreadMain() {
Console.WriteLine("Thread {0} started", Thread.CurrentThread.Name);
Thread.Sleep(30);
Console.WriteLine("Thread {0} started", Thread.CurrentThread.Name);
}
var t1 = new Thread(ThreadMain)
{
Name = "MyThread",
IsBackground = false
};
t1.Start();
结果为
如果将background换为true,则只输出一个信息因为main主线程结束了