C#多线程编程详解

2019-12-30 14:33:59于海丽

五、Task类

使用ThreadPool的QueueUserWorkItem()方法发起一次异步的线程执行很简单,但是该方法最大的问题是没有一个内建的机制让你知道操作什么时候完成,有没有一个内建的机制在操作完成后获得一个返回值。为此,可以使用System.Threading.Tasks中的Task类。

构造一个Task<TResult>对象,并为泛型TResult参数传递一个操作的返回类型。


namespace Test
{
  class Program
  {
    static void Main(string[] args)
    {
      Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
      t.Start();
      t.Wait();
      Console.WriteLine(t.Result);
      Console.ReadKey();
    }

    private static Int32 Sum(Int32 n)
    {
      Int32 sum = 0;
      for (; n > 0; --n)
        checked{ sum += n;} //结果太大,抛出异常
      return sum;
    }
  }
}

一个任务完成时,自动启动一个新任务。

一个任务完成后,它可以启动另一个任务,下面重写了前面的代码,不阻塞任何线程。


namespace Test
{
  class Program
  {
    static void Main(string[] args)
    {
      Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
      t.Start();
      //t.Wait();
      Task cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}",t.Result));
      Console.ReadKey();
    }

    private static Int32 Sum(Int32 n)
    {
      Int32 sum = 0;
      for (; n > 0; --n)
        checked{ sum += n;} //结果溢出,抛出异常
      return sum;
    }
  }
}

六、委托异步执行

委托的异步调用:BeginInvoke() 和 EndInvoke()


namespace Test
{
  public delegate string MyDelegate(object data);
  class Program
  {
    static void Main(string[] args)
    {
      MyDelegate mydelegate = new MyDelegate(TestMethod);
      IAsyncResult result = mydelegate.BeginInvoke("Thread Param", TestCallback, "Callback Param");

      //异步执行完成
      string resultstr = mydelegate.EndInvoke(result);
    }

    //线程函数
    public static string TestMethod(object data)
    {
      string datastr = data as string;
      return datastr;
    }

    //异步回调函数
    public static void TestCallback(IAsyncResult data)
    {
      Console.WriteLine(data.AsyncState);
    }
  }
}

七、线程同步

1)原子操作(Interlocked):所有方法都是执行一次原子读取或一次写入操作。

2)lock()语句:避免锁定public类型,否则实例将超出代码控制的范围,定义private对象来锁定。

3)Monitor实现线程同步

通过Monitor.Enter() 和 Monitor.Exit()实现排它锁的获取和释放,获取之后独占资源,不允许其他线程访问。

还有一个TryEnter方法,请求不到资源时不会阻塞等待,可以设置超时时间,获取不到直接返回false。