欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#線程間通信的異步機(jī)制

 更新時間:2022年05月25日 09:26:11   作者:springsnow  
這篇文章介紹了C#線程間通信的異步機(jī)制,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

線程間通信

我們看下面的圖

我們來看線程間通信的原理:線程(Thread B)和線程(Thread A)通信, 首先線程A 必須實現(xiàn)同步上下文對象(Synchronization Context), 線程B通過調(diào)用線程A的同步上下文對象來訪問線程A,所有實現(xiàn)都是在同步上下文中完成的.線程B有兩種方式來實現(xiàn)線程間的通信。

第一種:調(diào)用線程A的同步上下文對象,阻礙當(dāng)前線程,執(zhí)行紅色箭頭調(diào)用,直到黃色箭頭返回(同步上下文執(zhí)行完畢)才釋放當(dāng)前線程. (1->2->3->5)。

第二種:調(diào)用線程A的同步上下文對象(實際上是在開啟一個新線程去執(zhí)行,1->2->3->5) ,執(zhí)行紅色箭頭,但并不阻礙當(dāng)前線程(原有線程,1->4->5),綠色箭頭繼續(xù)執(zhí)行。

文章中將會通過下面幾個類來進(jìn)行介紹:

  • ISynchronizeInvoke 接口
  • SynchronizationContext 類
  • AsyncOperation / AsyncOperationManager 類

1. ISynchronizeInvoke 接口

我們先來看下面一段異步的代碼(Window Form控件下有1個Button/1個Label),但點擊Button的時候,執(zhí)行異步調(diào)用,完成后,告訴Window Form的 Label控件Text屬性”Asynchronous End”。

在windows應(yīng)用窗體應(yīng)用程序中,對窗體上控件屬性的任何修改都必須在主線程中完成。不能從其他線程安全地訪問控件的方法和屬性。

ISynchronizeInvoke 接口來自.Net Framework 1.0,提供3個方法1個屬性:

  • BeginInvoke / EndInvoke 方法 : 異步方法
  • Invoke 方法 : 同步方法
  • InvokeRequired 屬性 : 判讀來源的執(zhí)行線程
        delegate void DoWork();
        private void button1_Click(object sender, EventArgs e)
        {
            //更新狀態(tài),添加到Listbox 中
            AddValue("Asynchronous Start.");
            //使用委托來調(diào)用異步方法
            DoWork work = DoWorkMethod;
            work.BeginInvoke(OnWorkCallback, work);
        }

        void OnWorkCallback(IAsyncResult asyncResult)
        {
            DoWork work = asyncResult.AsyncState as DoWork;
            if (work != null)
            {
                work.EndInvoke(asyncResult);
            }
            //(1)方法:調(diào)用Control控件的Invoke
            //Action<string> asyncUpdateState = UpdateStatus; //Action<string> 介紹=> 附1
            //Invoke(asyncUpdateState, "1:Asynchronous End.");

            //(2)方法:直接在異步調(diào)用的線程下
            UpdateStatus("2:Asynchronous End.");
        }

        void UpdateStatus(string input)
        {
            //把你需要通知的控件Control 賦值給ISynchronizeInvoke
            //來實現(xiàn)線程間的通信
            ISynchronizeInvoke async = this.listBoxStatus;
            //使用(1)方法,InvokeRequired == false ,來源當(dāng)前(Window Form)主線程
            if (async.InvokeRequired == false)
                AddValue(input);
            else// 使用(2)方法 == true ,來源其他線程(異步)
            {
                Action<string> action = new Action<string>(status =>
                {
                    AddValue(status);
                });
                //調(diào)用ISynchronizeInvoke 提供的Invoke 同步方法,阻礙線程,直到調(diào)用結(jié)束
                //也可以使用ISynchronizeInvoke 提供的異步BeginInvoke/EndInvoke方法來實現(xiàn)調(diào)用.
                async.Invoke(action, new object[] { input });
            }
        }

        void AddValue(string input)
        {
            this.listBoxStatus.Items.Add(string.Format("[(#{2}){0}]Context is null:{1}", input, Thread.CurrentContext == null, Thread.CurrentThread.ManagedThreadId));
        }
        void DoWorkMethod()
        {
            Thread.Sleep(3000);//模擬耗時工作
        }

在代碼中(UpdateStatus方法體內(nèi)),我們可以看到主要是在ISynchronizeInvoke async = this.listBoxStatus;實現(xiàn)了線程間的通信,MSDN的解釋” 實現(xiàn)此接口的對象可以接收事件已發(fā)生的通知,并且可以響應(yīng)有關(guān)該事件的查詢”. 并使Window Form(主線程) 下的ListBox 控件和來自異步方法(另外一個線程)的建立了通道。
InvokeRequired 判斷線程的來源。

如果使用(1)方法,來源于Window Form 自身Control 的Invoke方法, InvokeRequired將返回false; 來源另外線程(異步)。

如果使用(2)返回true.同時ISynchronizeInvoke 提供了異步(BeginInvoke+EndInvok)和同步方法(Invoke)來實現(xiàn)線程間通信.Invoke 就是最上面的圖1 所示的第一種 / BeginInvoke+EndInvok 是第二種。

2. SynchronizationContext 類

相比ISynchronizeInvoke 接口,SynchronizationContext 類(來自.Net Framework 2.0)提供了更多的方法來操作同步上下文對象,實現(xiàn)線程間通信.在上面的例子中SynchronizationContext類中將由 Post/Send 方法來實現(xiàn)。

反編譯后我們看到:

  public virtual void Post(SendOrPostCallback d, object state)
 {
   ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);
 }

 public virtual void Send(SendOrPostCallback d, object state)
 {
   d(state);
 }
  • Send = ISynchronizeInvoke 中的Invoke 同步調(diào)用.圖1中的第一種
  • Post = ISynchronizeInvoke 中的BeginInvoke + EndInvoke異步調(diào)用. 圖1中的第二種

SynchronizationContext 類舉例(在WinForm 下編程)

      delegate void DoWork();
   private void button1_Click(object sender, EventArgs e)
   {
     //System.Windows.Forms.Form 自動的創(chuàng)建默認(rèn)的同步上下文對象,
     //直接的獲取當(dāng)前的同步上下文對象
     SynchronizationContext context = SynchronizationContext.Current;
     //更新狀態(tài),添加到Listbox 中
     AddValue<string>("Asynchronous Start.");
     //使用委托來調(diào)用異步方法
      DoWork work = DoWorkMethod;
      work.BeginInvoke(OnWorkCallback, context);

    }
    void OnWorkCallback(IAsyncResult asyncResult)
    {
      AsyncResult async = (AsyncResult)asyncResult;
      DoWork work = (DoWork)async.AsyncDelegate;
      work.EndInvoke(asyncResult);
      
      //更新狀態(tài)
      UpdateStatus("Asynchronous End.", asyncResult.AsyncState);
    }
    void UpdateStatus(object input,object syncContext)
    {
      //獲取主線程(Window Form)中同步上下文對象
      SynchronizationContext context = syncContext as SynchronizationContext;
      //使用SynchronizationContext 類中異步Post 方法
      SendOrPostCallback callback = new SendOrPostCallback(p => {
        AddValue<object>(p);
      });
      context.Post(callback, input);//Post 為異步,Send 為同步

    }
    void AddValue<T>(T input)
    {
      this.listBoxStatus.Items.Add(string.Format("[(#{2}){0}]Context is null:{1}", input, Thread.CurrentContext == null, Thread.CurrentThread.ManagedThreadId));
    }
    void DoWorkMethod()
    {
      Thread.Sleep(3000);//模擬耗時工作
    }

上面我們已經(jīng)說過在主線程中System.Windows.Forms.Form 自動的創(chuàng)建默認(rèn)的同步上下文對象, 這時候我們把當(dāng)前的同步上下文對象通過參數(shù)的形式賦值到異步線程中,調(diào)用Post 方法來實現(xiàn), Post 方法接收 SendOrPostCallback 委托和額外object state參數(shù),在Post方法體內(nèi)調(diào)用線程池的線程來實現(xiàn)(Code2.1).當(dāng)然我們也可以直接使用Send方法。

下面我們看看線程中的代碼(在Console 下編程)。

  static class Program
 {
   static void Main()
   {
     Output("Main Thread Start.");
     //為主線程創(chuàng)建Synchronization Context
     var context = new SynchronizationContext();
     //開始一個新線程
     Thread threadB = new Thread(work);
      threadB.Start(context);

      Console.Read();
    }
    static void work(object context)
    {
      Output("Thread B");

      //獲取主線程中的同步上下文對象
      SynchronizationContext sc = context as SynchronizationContext;

      //異步的方式和主線程通信,并發(fā)送"Hello World".
      sc.Post(new SendOrPostCallback(p =>
      {
        Output(p);
      }), "Hello World");
    }
    static void Output(object value)
    {
      Console.WriteLine("[ThreadID:#{0}]{1}", Thread.CurrentThread.ManagedThreadId, value);
    }
  }

在主線程中因為沒有同步上下文對象,所以開始我們new SynchronizationContext(); 對象,其他和上面基本一樣.此例說明了Post 是開啟新線程(線程池)運(yùn)行的。

3. AsyncOperation / AsyncOperationManager 類

AsyncOperation / AsyncOperationManager 類是SynchronizationContext 類的進(jìn)一步封裝和實現(xiàn), AsyncOperationManager在創(chuàng)建AsyncOperation對象的時候會取得當(dāng)前線程的同步上下文對象,并存儲在AsyncOperation之中,使我們訪問同步上下文對象更加容易。

  public class MySynchronizedClass
 {
   private AsyncOperation operation;
   public event EventHandler somethingHappened;
   public MySynchronizedClass()
   {
     //創(chuàng)建AsyncOperation 對象,并把當(dāng)前線程的同步上下文保持到AsyncOperation中.
     operation = AsyncOperationManager.CreateOperation(null);

      Thread workerThread = new Thread(new ThreadStart(DoWork));
      workerThread.Start();
    }

    private void DoWork()
    {
      SendOrPostCallback callback = new SendOrPostCallback(state =>
       {
         EventHandler handler = somethingHappened;

         if (handler != null)
         {
           handler(this, EventArgs.Empty);
         }
       });

      operation.Post(callback, null);
      //注意1
      operation.OperationCompleted();
    }
  }

AsyncOperation類中實現(xiàn)了OperationCompleted的方法. SynchronizationContext 類中這個方法是沒有具體的代碼實現(xiàn)的。

到此這篇關(guān)于C#線程間異步通信的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#中Task.ContinueWith連續(xù)任務(wù)使用實例

    C#中Task.ContinueWith連續(xù)任務(wù)使用實例

    本文主要介紹了C#中Task.ContinueWith連續(xù)任務(wù)使用實例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#使用Task實現(xiàn)異步方法

    C#使用Task實現(xiàn)異步方法

    本文主要介紹了C#使用Task實現(xiàn)異步方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • c#高效的線程安全隊列ConcurrentQueue<T>的實現(xiàn)

    c#高效的線程安全隊列ConcurrentQueue<T>的實現(xiàn)

    這篇文章主要介紹了c#高效的線程安全隊列ConcurrentQueue<T>的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • C#開發(fā)微信門戶及應(yīng)用(2) 微信消息處理和應(yīng)答

    C#開發(fā)微信門戶及應(yīng)用(2) 微信消息處理和應(yīng)答

    文章主要為大家詳細(xì)介紹了C#開發(fā)微信門戶及應(yīng)用第二篇,微信消息處理和應(yīng)答,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • C# 如何調(diào)用C++ dll string類型返回

    C# 如何調(diào)用C++ dll string類型返回

    這篇文章主要介紹了C# 如何調(diào)用C++ dll string類型返回問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 在C#中g(shù)lobal關(guān)鍵字的作用及其用法

    在C#中g(shù)lobal關(guān)鍵字的作用及其用法

    global 是 C# 2.0 中新增的關(guān)鍵字,理論上說,如果代碼寫得好的話,根本不需要用到它,但是不排除一些特別的情況,比如修改別人的代碼,本文僅舉例說明。
    2016-03-03
  • 詳解WPF中的對象資源

    詳解WPF中的對象資源

    這篇文章主要介紹了WPF中對象資源的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用WPF,感興趣的朋友可以了解下
    2021-04-04
  • C#使用CryptoStream類加密和解密字符串的實現(xiàn)

    C#使用CryptoStream類加密和解密字符串的實現(xiàn)

    CryptoStream設(shè)計用于在內(nèi)容以流的形式輸出到文件時加密和解密內(nèi)容,本文主要介紹了C#使用CryptoStream類加密和解密字符串的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • C#從文件流讀取xml文件到DataSet并顯示的方法

    C#從文件流讀取xml文件到DataSet并顯示的方法

    這篇文章主要介紹了C#從文件流讀取xml文件到DataSet并顯示的方法,實例分析了C#操作XML文件的技巧與DataSet的使用方法,需要的朋友可以參考下
    2015-04-04
  • C#制作鷹眼的詳細(xì)全過程(帶注釋)實例代碼

    C#制作鷹眼的詳細(xì)全過程(帶注釋)實例代碼

    C#制作鷹眼的詳細(xì)全過程(帶注釋)實例代碼,需要的朋友可以參考一下
    2013-03-03

最新評論