C#之线程、任务和同步

异步委托

创建线程的一个简单的方式就是定义一个委托进行异步调用,异步调用委托的方式有三种:投票等待句柄异步回调

.投票

通过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类构造函数重载为接收ThreadStartParameterizedThreadStart类型的委托参数.
只要有一个前台线程在运行,应用程序的进程就在运行。如果多个前台线程在运行,而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主线程结束了

线程优先级
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值