WinForm 異步調用方法


假如要在一個線程中異步執行一個方法,則先創建一個該方法的委托類型,然后CLR會自動為該委托類型定義一個BeginInvoke方法和EndInvoke方法,我們就靠這兩個方法異步調用委托類型指向的方法(這句話有點繞口,呵呵)

BeginInvoke這個方法用於啟動異步調用,該方法具有和要異步執行的方法具有相同的參數列表,只不過又多加了兩個參數,多加的那兩個參數的作用在后面介紹。執行BeginInvoke方法后,將立即返回一個IAsyncResult,用於監視被調用方法執行的進度。

EndInvoke這個方法用於得到異步調用的結果,調用BeginInvoke方法后隨時可以調用EndInvoke方法,假如異步調用還沒有完成,EndInvoke會阻塞到異步調用執行完畢,EndInvoke的參數包括被調用方法的out和ref參數,還有在調用BeginInvoke方法時得到的那個IAsyncResult(好像就是一個哈希表的key,可以靠這個key去得到相應的線程,這樣就可以處理多線程而不至於混亂了)

第一種方法:使用BeginInvoke方法后,主線程去執行一些操作,然后再使用EndInvoke方法等待被調用方法完成,以下是示例代碼

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
  class AsyncDemo // 我定義了一個演示的類,里面有一個測試方法TestMethod 其實完全可以把這個TestMethod寫到Main()函數的同一個類中,只不過寫成static方法即可
  {
    public string TestMethod(int callDuration, out int threadid)
    {
        Console.WriteLine("Test Method begins");
        Thread.Sleep(callDuration);//睡眠callDuration指定的毫秒
        threadid = AppDomain.GetCurrentThreadId();//獲取當前線程的id
        return "MyCallTime was" + callDuration.ToString();//返回當前線程睡眠的時間

    }
  }
  public delegate string AsyncDelegate(int callDuration, out int threadid); //創建一個AsyncDemo類中TestMethod方法相同簽名的委托類型

  class Program
  {
    static void Main(string[] args)
    {
        int threadID;
        AsyncDemo ad = new AsyncDemo();//聲明一個AsyncDemo類型的對象ad,並創建一個實例賦給它
        AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);//聲明一個AsyncDelegate類型的對象andl,並讓他指向ad對象的TestMethod方法
        IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);//執行andl的BeginInvoke方法,返回一個IAsyncResult類型的實例對象給ar變量,其實是一個號碼牌(不知道這樣說是否形象)
        Thread.Sleep(10);//使當前線程睡眠10毫秒(其實可去掉這句,我寫這個的目的是確保異步線程已啟動,再執行以下語句)
        Console.WriteLine("Main Thread {0} Does Some Work",
          AppDomain.GetCurrentThreadId());//輸出當前線程的id
        string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke方法,傳入out或ref類型參數和在調用BeginInvoke方法時得到的IAsyncResult,此時主線程將等待異步調用執行完畢,返回結果后執行以下語句
        Console.WriteLine("The call executed on thread {0},with return value : {1}",
          threadID, ret);
        Console.ReadLine();
    }
  }
}


ok,以上是第一種直接使用EndInvoke來等待異步調用完成的方法 
================================================
================================================

第二種方法是借助返回的IAsyncHandle的WaitHandle屬性的WaitOne()方法實現線程同步后,執行代碼,然后將要執行的代碼執行后隨時可調用EndInvoke方法。

示例代碼基本沒有什么改動,只是在BeginInvoke方法后執行一個ar.WaitHandle.WaitOne()方法,該方法將阻塞主線程使主線程等待返回ar的begininvoke調用的方法的線程執行完畢(不要怪我說話有點繞,我是說的詳細,否則你弄不明白,仔細看這句話就明白了^o^)。

本着一切代碼都是紙老虎的原則,請仔細分析下面的代碼 其實和示例1基本無異 ,只是使用WaitOne()方法同步了一下線程而已

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
  class AsyncDemo
  {
    public string TestMethod(int callDuration, out int threadid)
    {
        Console.WriteLine("Test Method begins");
        Thread.Sleep(callDuration);
        threadid = AppDomain.GetCurrentThreadId();
        return "MyCallTime was" + callDuration.ToString();
    }
  }
  public delegate string AsyncDelegate(int callDuration, out int threadid);
  class Program
  {
    static void Main(string[] args)
    {
        int threadID;
        AsyncDemo ad = new AsyncDemo();
        AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);
        IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);
        Thread.Sleep(10);
        Console.WriteLine("Main Thread {0} Does Some Work",
          AppDomain.GetCurrentThreadId());
        ar.AsyncWaitHandle.WaitOne();//執行該方法時主線程將等待輔助線程執行完畢,使兩線程同步后再執行以下語句
        Console.WriteLine("其實很簡單");//執行一些方法
        string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke來獲取返回結果和傳入ref和out的變量獲取修改后的實例的位置(這我就不太好用語言來表述了,你自己心領神會吧)
        Console.WriteLine("The call executed on thread {0},with return value : {1}",
          threadID, ret);
        Console.ReadLine();
    }
  }
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM