<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      無(wú)論是WIN32還是Windows Form還是WPF還是Swing,都不支持GUI線程之外的線程直接訪問(wèn)其API。今天我們來(lái)回顧一下這個(gè)發(fā)展過(guò)程。一個(gè)普通的操作是怎么被封裝封裝再封裝的。

      Win32

      在Windows SDK時(shí)代,我們都知道,界面就是一個(gè)大的WndProc控制的。

      switch (message)
      {
      case WM_PAINT:

      case WM_DESTROY:

      default:
      return DefWindowProc(hWnd, message, wParam, lParam);
      }

      如果我們需要另外一個(gè)線程去做一些耗時(shí)的IO操作,同時(shí)要回調(diào)回來(lái)更新的界面,這個(gè)時(shí)候要么自己定義一個(gè)回調(diào)隊(duì)列,然后在WM_IDLE的時(shí)候處理,要么就利用窗口本身的消息隊(duì)列,自己創(chuàng)建一個(gè)消息類(lèi)型:

      // at startup
      int OUR_APP_IO_COMPLETED = RegisterWindowMessage("OUR_APP_IO_COMPLETED");
      ----
      // after io completed
      PostMessage(hwnd, OUR_APP_IO_COMPLETED, xxx, xxx);

      這樣,我們就可以讓界面更新的操作在GUI線程完成了。

      .NET 1.0 Windows Forms

      Windows Forms的出現(xiàn)使得很多東西簡(jiǎn)單多了。跨線程的GUI操作也簡(jiǎn)化了許多。因?yàn)槲覀冇辛薉elegate和Control.Invoke。前者就是一個(gè)函數(shù)指針的升級(jí)版,Control.Invoke就是PostMessage的升級(jí)版:

      public delegate void IOCompletedHandler();
      public void OnIOCompleted() {
      control.Invoke(
      new IOCompletedHandler(HandleIOCompleted));
      }
      public void HandleIOCompleted() {

      }

      在內(nèi)部Control維護(hù)了一個(gè)threadCallbackList。調(diào)用Invoke相當(dāng)于

      1、把Delegate和參數(shù)封裝到一起,壓入到threadCallbackList中

      2、確保ThreadCallbackMessage被注冊(cè)了(RegisterWindowMessage)

      3、PostMessage,觸發(fā)Callback

      4、WaitForHandle,等待GUI線程完成處理(如果是BeginInvoke則可以省略這個(gè)步驟)

      而Windows Forms的WndProc的消息循環(huán),就需要加一個(gè)case語(yǔ)句,來(lái)響應(yīng)PostMessage。在得到消息的同時(shí),去threadCallbackList中取出需要回調(diào)的Delegate,然后一一調(diào)用。

      Control.Invoke確實(shí)是讓我們的生活方便很多。但是它還是不能避免所謂的BeginInvoke之舞(BeginInvoke Dance):

      //http://ikriv.com:8765/en/prog/info/dotnet/MysteriousHang.html
      delegate
      void MyHandlerDelegate();
      void MyHandler()
      {
      // "The BeginInvoke dance"
      if (this.InvokeRequired) // assuming this descends from Control
      {
      BeginInvoke(
      new MyHandlerDelegate(MyHandler) );
      return;
      }
      // assume we are on the main GUI thread
      do GUI stuff
      }

      InvokeRequired內(nèi)部實(shí)現(xiàn)就是線程安全地比較一下當(dāng)前線程和GUI線程的線程ID是不是相等的。

      另外Control.Invoke還需要我們確保對(duì)應(yīng)的Control的句柄已經(jīng)創(chuàng)建。為了避免這個(gè)問(wèn)題,WinForm有一個(gè)MarshingControl可以給我們使用。

       

      Application.ThreadContext.FromCurrent().MarshingControl;

       

      .NET 2.0 Windows Forms

      如果我提供了一個(gè)回調(diào)接口。我一般會(huì)直接調(diào)用回調(diào)方法,如果我知道回調(diào)方法必須在GUI線程中執(zhí)行的話,用必須用Control.Invoke來(lái)調(diào)用回調(diào)方法。所以,在缺乏信息的情況下,回調(diào)接口的提供者是沒(méi)有辦法保證回調(diào)方法的執(zhí)行線程的環(huán)境的。所以,按照Strategy模式,我們可以定義一個(gè)CallbackStrategy

      public interface CallbackExecutor {
      void Execute(Delegate callback, object[] args);
      }
      public class DefaultCallbackExecutor : CallbackExecutor {
      public void Execute(Delegate callback, object[] args) {
      callback.Invoke(args);
      }
      }
      public class WindowsFormsCallbackExecutor : CallbackExecutor {
      private Control marshalingControl;
      public WindowsFormsCallbackExecutor() {
      Application.ThreadContext context
      = Application.ThreadContext.FromCurrent();
      if (context != null)
      {
      this.marshalingControl= context.MarshalingControl;
      }
      }
      public void Execute(Delegate callback, object[] args) {
      marshalingControl.Invoke(callback, args);
      }
      }

      然后回調(diào)方法的提供者就不用為難了,它只要調(diào)用CallbackExecutor就可以了,同時(shí)回調(diào)方法也可以安心地直接去干自己的事情。從而,誰(shuí)都不需要做BeginInvoke Dance了。

      這就是.NET引入的SynchronizationContext的基本原理。由于微軟不是接口愛(ài)好者,所以它省去了共同的那個(gè)接口,直接讓W(xué)indowsFormSynchronizationContext繼承自SynchronizationContext類(lèi)了。SynchronizationContext是線程唯一的,取得當(dāng)前線程的Sync Context可以使用:

       

      SynchronizationContext.Current.Post(delegate{//your code}, null);

       

      與SynchronizationContext類(lèi)同時(shí)引入的還有AsyncOperationManager,AsyncOperation。它又是SynchronizationContext的封裝。一般來(lái)說(shuō),推薦使用AsyncOperationManager。AsyncOperationManager在創(chuàng)建AsyncOperation的時(shí)候會(huì)取得當(dāng)前線程的Sync Context,并存儲(chǔ)在SyncOperation之中。 所以后來(lái)利用AsyncOperation來(lái)回調(diào)的時(shí)候,就會(huì)用一開(kāi)始創(chuàng)建時(shí)候所在線程的context來(lái)回調(diào)。

      // initialize in GUI thread
      asyncOperation = AsyncOperationManager.Create(null);

      // when you want to call back
      asyncOperation.Post(delegate{//your code}, null);

      像BackgroundWorker這樣的類(lèi),之所以其Callback可以直接訪問(wèn)GUI,其秘訣就在于回調(diào)不是直接調(diào)用的,而是有 AsyncOperation來(lái)間接代勞的。只要AsyncOperation是在GUI線程創(chuàng)建的,所有由它代勞的回調(diào)都會(huì)經(jīng)過(guò) MarshalingControl來(lái)做Control.Invoke。

      .NET 3.0 WPF

      Control.Invoke變成了Dispatcher.Invoke。內(nèi)部實(shí)現(xiàn)還是一樣的,有一個(gè)Callback隊(duì)列,然后PostMessage。同時(shí)引入的還有DispatcherSynchronizationContext。

      Conculsion

      從直接PostMessage到Control.Invoke到SynchronizationContext到AsyncOperationManager到BackgroundWorker,職責(zé)最終推卸到了回調(diào)的提供方。但是由于引入的時(shí)間不一致,很多回調(diào)提供方是沒(méi)有使用AsyncOperation的。這個(gè)時(shí)候,我們自己需要自己去包裝,比如:

      Code

      這樣,我們就不需要在手工地去用Control.Invoke了,也不應(yīng)該再直接用Control.Invoke了。

       

       

       

      posted on 2008-11-03 07:58  taowen  閱讀(2805)  評(píng)論(4)    收藏  舉報(bào)
      主站蜘蛛池模板: av天堂午夜精品一区| 孕妇特级毛片ww无码内射| 亚洲热妇无码av在线播放| 欧美人与动牲交a免费| 久久国产精品不只是精品| 日韩成人精品一区二区三区| 亚洲精品无码日韩国产不卡av| 亚洲国产色婷婷久久99精品91| 九九在线精品国产| 无码人妻精品一区二区三区东京热| 国内精品人妻一区二区三区 | 亚洲国产精品18久久久久久| 吴旗县| 国产精品三级黄色小视频| 虎白女粉嫩尤物福利视频| 欧美成人午夜精品免费福利| 国产国语一级毛片| 国产午夜福利不卡在线观看| 亚洲欧洲日产国码久在线| 国产日韩精品一区在线不卡| 亚洲最大天堂在线看视频| 熟女人妻aⅴ一区二区三区电影| 精品无码国产一区二区三区av | 亚洲欧美综合在线天堂| 中文字幕有码高清日韩| 亚洲国产成人精品激情姿源| 日韩中文字幕人妻一区| 成年女人黄小视频| 无码av岛国片在线播放| 性虎精品无码AV导航| 耒阳市| 亚洲高清aⅴ日本欧美视频| 亚洲AV无码精品色午夜果冻 | 国产色悠悠综合在线观看| 日本欧美大码a在线观看| 孟连| 亚洲av日韩av中文高清性色| 亚洲色欲色欲www在线看| 亚洲国产成人综合精品| 久久精品激情亚洲一二区| AV最新高清无码专区|