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

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

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

      Kevin-moon

      學習在于分享
        博客園  :: 首頁  :: 新隨筆  :: 聯(lián)系 :: 訂閱 訂閱  :: 管理

      線程之間的通訊---SynchronizationContext

      Posted on 2009-01-13 08:58  Kevin-moon  閱讀(18824)  評論(36)    收藏  舉報
           過年前的這段時間真是舒服,沒有了平時項目發(fā)版的緊張,剩下的就是只有在網(wǎng)上閑逛了,哈哈!
           今天早上閑逛的時候,在CodeProject發(fā)現(xiàn)了個不錯的文章,英文好的直接去http://www.codeproject.com/KB/threads/SynchronizationContext.aspx看吧,不好,就將就的看下我的吧,呵呵!(沒有直接翻譯,不過大概的思路相同)

      理解SynchronizationContext


        SynchronizationContext 類是一個基類,可提供不帶同步的自由線程上下文。 此類實現(xiàn)的同步模型的目的是使公共語言運行庫內(nèi)部的異步/同步操作能夠針對不同的異步模型采取正確的行為。此模型還簡化了托管應用程序為在不同的同步環(huán)境下正常工作而必須遵循的一些要求。同步模型的提供程序可以擴展此類并為這些方法提供自己的實現(xiàn)。(來自MSDN)
        簡而言之就是允許一個線程和另外一個線程進行通訊,SynchronizationContext在通訊中充當傳輸者的角色。另外這里有個地方需要清楚的,不是每個線程都附加SynchronizationContext這個對象,只有UI線程是一直擁有的。
        這里你可能有個問題:對于UI線程來說,是如何將SynchronizationContext這個對象附加到線程上的呢?!OK,我們先從下面的代碼開始,

       

      [STAThread]
      static void Main()
      {
          Application.EnableVisualStyles();
          Application.SetCompatibleTextRenderingDefault(
      false);

          
      // let's check the context here
          var context = SynchronizationContext.Current;
          
      if (context == null)
              MessageBox.Show(
      "No context for this thread");
          
      else
              MessageBox.Show(
      "We got a context");

          
      // create a form
          Form1 form = new Form1();

          
      // let's check it again after creating a form
          context = SynchronizationContext.Current;

          
      if (context == null)
              MessageBox.Show(
      "No context for this thread");
          
      else
              MessageBox.Show(
      "We got a context");

          
      if (context == null)
              MessageBox.Show(
      "No context for this thread");

          Application.Run(
      new Form1());
      }

      運行結果:
      1、No context for this thread
      2、We got a context

           
           從運行結果來看,在Form1 form = new Form1()之前,SynchronizationContext對象是為空,而當實例化Form1窗體后,SynchronizationContext對象就被附加到這個線程上了。所以可以得出答案了:當Control對象被創(chuàng)建的同時,SynchronizationContext對象也會被創(chuàng)建并附加到線程上。
           好的,我們既然已經(jīng)基本了解了SynchronizationContext,接下來的事情就是使用它了!

      如何使用SynchronizationContext


        應用程序有兩個線程:線程A和線程B,不過線程B比較特殊,它屬于UI線程,當這兩個線程同時運行的時候,線程A有個需求:"修改UI對象的屬性",這時候如果你是線程A,你會如何去完成需求呢?!

      第一種方式:
           
           在線程A上面直接去操作UI對象,這是線程B說:"線程A,你真xx,你不知道我的特殊嘛!",然后直接拋給線程A一個異常信息,線程A得到異常后,一臉的無辜和無奈.....!

      第二種方式:
        InvokeRequired?!是的,當然沒問題。(解釋下,InvokeRequired屬性是每個Control對象都具有的屬性,它會返回true和false,當是true的時候,表示它在另外一個線程上面,這是必須通過Invoke,BeginInvoke這些方法來調用更新UI對象的方法,當是false的時候,有兩種情況,1:位于當前線程上面,可以通過直接去調用修改UI對象的方法,2:位于不同的線程上,不過控件或窗體的句柄不存在。對于句柄是否存在的判斷,可以通過IsHandleCreated來獲取,如果句柄不存在,是不能調用Invoke...這些方法的,這時候你必須等待句柄的創(chuàng)建
      通過InvokeRequired的實現(xiàn)方式如下:
      using System;
      using System.Drawing;
      using System.Windows.Forms;
      using System.Threading;

         
      public class MyFormControl : Form
         {
            
      public delegate void AddListItem(String myString);
            
      public AddListItem myDelegate;
            
      private Button myButton;
            
      private Thread myThread;
            
      private ListBox myListBox;
            
      public MyFormControl()
            {
               myButton 
      = new Button();
               myListBox 
      = new ListBox();
               myButton.Location 
      = new Point(72160);
               myButton.Size 
      = new Size(15232);
               myButton.TabIndex 
      = 1;
               myButton.Text 
      = "Add items in list box";
               myButton.Click 
      += new EventHandler(Button_Click);
               myListBox.Location 
      = new Point(4832);
               myListBox.Name 
      = "myListBox";
               myListBox.Size 
      = new Size(20095);
               myListBox.TabIndex 
      = 2;
               ClientSize 
      = new Size(292273);
               Controls.AddRange(
      new Control[] {myListBox,myButton});
               Text 
      = " 'Control_Invoke' example ";
               myDelegate 
      = new AddListItem(AddListItemMethod);
            }
            
      static void Main()
            {
               MyFormControl myForm 
      = new MyFormControl();
               myForm.ShowDialog();
            }
            
      public void AddListItemMethod(String myString)
            {
                  myListBox.Items.Add(myString);
            }
            
      private void Button_Click(object sender, EventArgs e)
            {
               myThread 
      = new Thread(new ThreadStart(ThreadFunction));
               myThread.Start();
            }
            
      private void ThreadFunction()
            {
               MyThreadClass myThreadClassObject  
      = new MyThreadClass(this);
               myThreadClassObject.Run();
            }
         }
         
      public class MyThreadClass
         {
            MyFormControl myFormControl1;
            
      public MyThreadClass(MyFormControl myForm)
            {
               myFormControl1 
      = myForm;
            }
            String myString;

            
      public void Run()
            {
               
      for (int i = 1; i <= 5; i++)
               {
                  myString 
      = "Step number " + i.ToString() + " executed";
                  Thread.Sleep(
      400);
                  
      // Execute the specified delegate on the thread that owns
                  
      // 'myFormControl1' control's underlying window handle with
                  
      // the specified list of arguments.
                  myFormControl1.Invoke(myFormControl1.myDelegate,
                                         
      new Object[] {myString});
               }
            }
         }

          不過這里存在一個有爭論的地方:這種方式必須通過調用Control的Invoke方法來實現(xiàn),這就是說調用的地方必須有一個Control的引用存在。
        看下MyThreadClass類,這個類中就存在MyFormControl的引用對象。其實如果這個類放在這里是沒有任務不妥之處的,但是如果把MyThreadClass類放在業(yè)務層,這時候問題就出現(xiàn)了,從設計角度來說,業(yè)務層是不允許和UI有任何關系,所以MyFormControl的引用對象絕對不能存在于MyThreadClass類,但是不讓它存在,更新UI控件的需求就滿足不了,這種情況下,我們?nèi)绾巫龅揭环N最佳方案呢!?

      第三種方式:
        本文的主角:SynchronizationContext登場了。解釋之前,先讓下面的代碼做下鋪墊,
      public partial class Form1 : Form
      {
          
      public Form1()
          {
              InitializeComponent();
          }

          
      private void mToolStripButtonThreads_Click(object sender, EventArgs e)
          {
              
      // let's see the thread id
              int id = Thread.CurrentThread.ManagedThreadId;
              Trace.WriteLine(
      "mToolStripButtonThreads_Click thread: " + id);

              
      // grab the sync context associated to this
              
      // thread (the UI thread), and save it in uiContext
              
      // note that this context is set by the UI thread
              
      // during Form creation (outside of your control)
              
      // also note, that not every thread has a sync context attached to it.
              SynchronizationContext uiContext = SynchronizationContext.Current;

              
      // create a thread and associate it to the run method
              Thread thread = new Thread(Run);

              
      // start the thread, and pass it the UI context,
              
      // so this thread will be able to update the UI
              
      // from within the thread
              thread.Start(uiContext);
          }

          
      private void Run(object state)
          {
              
      // lets see the thread id
              int id = Thread.CurrentThread.ManagedThreadId;
              Trace.WriteLine(
      "Run thread: " + id);

              
      // grab the context from the state
              SynchronizationContext uiContext = state as SynchronizationContext;

              
      for (int i = 0; i < 1000; i++)
              {
                  
      // normally you would do some code here
                  
      // to grab items from the database. or some long
                  
      // computation
                  Thread.Sleep(10);

                  
      // use the ui context to execute the UpdateUI method,
                  
      // this insure that the UpdateUI method will run on the UI thread.

                  uiContext.Post(UpdateUI, 
      "line " + i.ToString());
              }
          }

          
      /// <summary>
          
      /// This method is executed on the main UI thread.
          
      /// </summary>
          private void UpdateUI(object state)
          {
              
      int id = Thread.CurrentThread.ManagedThreadId;
              Trace.WriteLine(
      "UpdateUI thread:" + id);
              
      string text = state as string;
              mListBox.Items.Add(text);
          }
      }

      運行結果:

      mToolStripButtonThreads_Click thread: 10
      Run thread: 
      3
      UpdateUI thread:
      10
      UpdateUI thread:
      10
      UpdateUI thread:
      10
      UpdateUI thread:
      10
       (x1000 times)

          程序首先在Form1窗體的mToolStripButtonThreads_Click事件中,獲取當前的SynchronizationContext對象,然后啟動另外一個線程,并且將SynchronizationContext對象傳遞給啟動的線程,啟動的線程通過SynchronizationContext對象的Post方法來調用一個委托方法UpdateUI,因為UpdateUI是執(zhí)行在主UI線程上的,所以可以通過它來修改UI上對象的信息。
          怎么樣!不錯吧,現(xiàn)在我們可以把Control引用給拋棄了,哈哈!
          如果你去查下MSDN,會發(fā)現(xiàn)SynchronizationContext還有一個Send方法,Send和Post有什么區(qū)別?

      Send VS Post,以及異常處理


      首先看下異常處理的情況
      private void Run(object state)
      {
          
      // let's see the thread id
          int id = Thread.CurrentThread.ManagedThreadId;
          Trace.WriteLine(
      "Run thread: " + id);

          
      // grab the context from the state
          SynchronizationContext uiContext = state as SynchronizationContext;

          
      for (int i = 0; i < 1000; i++)
          {
              Trace.WriteLine(
      "Loop " + i.ToString());
              
      // normally you would do some code here
              
      // to grab items from the database. or some long
              
      // computation
              Thread.Sleep(10);

              
      // use the ui context to execute the UpdateUI method, this insure that the
              
      // UpdateUI method will run on the UI thread.

              
      try
              {
                  uiContext.Send(UpdateUI, 
      "line " + i.ToString());
              }
              
      catch (Exception e)
              {
                  Trace.WriteLine(e.Message);
              }
          }
      }

      /// <summary>
      /// This method is executed on the main UI thread.
      /// </summary>
      private void UpdateUI(object state)
      {
          
      throw new Exception("Boom");
      }

         當你運行的時候, 你可能希望在UI線程上面去拋出,但是結果往往出忽你的意料,異常信息都在Run方法的線程上被捕獲了。這時候你可能想問:WHY?!
         解釋之前,我們先看下,Send VS Post的結果:
         Send 方法啟動一個同步請求以發(fā)送消息
         Post 方法啟動一個異步請求以發(fā)送消息。    
         哈哈,異常處理的答案迎韌而解了吧!

          今天就寫到這里吧,下一篇和大家討論下SynchronizationContext是否在所有線程中都適用...

       

      主站蜘蛛池模板: 韩国无码AV片午夜福利| 国产午夜精品一区二区三| 一本一本久久A久久精品综合不卡| 免费国产高清在线精品一区| 日韩毛片在线视频x| 久久亚洲精品亚洲人av| 无码电影在线观看一区二区三区| 瑞昌市| 日韩精品亚洲精品第一页| 精品国产中文字幕懂色| 国产成人精品电影在线观看| 天天躁日日躁狠狠躁性色avq| 亚洲欧美日韩愉拍自拍美利坚| 宜黄县| 一本无码在线观看| 成年在线观看免费人视频| 亚洲欧美人成电影在线观看| 亚洲大尺度一区二区av| 女人下边被添全过视频的网址| 国产精品成人网址在线观看| 国内少妇偷人精品免费| 中文字幕热久久久久久久| 亚洲自拍偷拍福利小视频| 中文字幕人妻无码一夲道| 国产成人精品亚洲资源| 国产精品成| 午夜精品久久久久久久久| 日韩乱码人妻无码中文字幕视频| 色吊丝中文字幕在线观看| 久久久精品2019中文字幕之3| 国内熟妇人妻色在线视频| 91福利视频一区二区| 午夜av高清在线观看| 久青草精品视频在线观看| 午夜免费无码福利视频麻豆| 亚洲香蕉免费有线视频| 绝顶丰满少妇av无码| 在线看国产精品自拍内射| 色欲久久综合亚洲精品蜜桃| 亚洲av免费成人在线| 午夜福利片1000无码免费|