• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 224  文章 - 41  trackbacks - 0
            <2008年11月>
            2627282930311
            2345678
            9101112131415
            16171819202122
            23242526272829
            30123456

            享受編程

            常用鏈接

            留言簿(11)

            隨筆分類(159)

            隨筆檔案(224)

            文章分類(2)

            文章檔案(4)

            經典c++博客

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            原文地址:http://www.cnblogs.com/Kevin-moon/archive/2009/01/13/1374353.html

             過年前的這段時間真是舒服,沒有了平時項目發版的緊張,剩下的就是只有在網上閑逛了,哈哈!
                 今天早上閑逛的時候,在CodeProject發現了個不錯的文章,英文好的直接去http://www.codeproject.com/KB/threads/SynchronizationContext.aspx看吧,不好,就將就的看下我的吧,呵呵!(沒有直接翻譯,不過大概的思路相同)

            理解SynchronizationContext


              SynchronizationContext 類是一個基類,可提供不帶同步的自由線程上下文。 此類實現的同步模型的目的是使公共語言運行庫內部的異步/同步操作能夠針對不同的異步模型采取正確的行為。此模型還簡化了托管應用程序為在不同的同步環境下正常工作而必須遵循的一些要求。同步模型的提供程序可以擴展此類并為這些方法提供自己的實現。(來自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對象被創建的同時,SynchronizationContext對象也會被創建并附加到線程上。
                 好的,我們既然已經基本了解了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...這些方法的,這時候你必須等待句柄的創建
            通過InvokeRequired的實現方式如下:
            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方法來實現,這就是說調用的地方必須有一個Control的引用存在。
              看下MyThreadClass類,這個類中就存在MyFormControl的引用對象。其實如果這個類放在這里是沒有任務不妥之處的,但是如果把MyThreadClass類放在業務層,這時候問題就出現了,從設計角度來說,業務層是不允許和UI有任何關系,所以MyFormControl的引用對象絕對不能存在于MyThreadClass類,但是不讓它存在,更新UI控件的需求就滿足不了,這種情況下,我們如何做到一種最佳方案呢!?

            第三種方式:
              本文的主角: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是執行在主UI線程上的,所以可以通過它來修改UI上對象的信息。
                怎么樣!不錯吧,現在我們可以把Control引用給拋棄了,哈哈!
                如果你去查下MSDN,會發現SynchronizationContext還有一個Send方法,Send和Post有什么區別?

            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 方法啟動一個同步請求以發送消息
               Post 方法啟動一個異步請求以發送消息。    
               哈哈,異常處理的答案迎韌而解了吧!

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

             

            posted on 2010-09-07 12:10 漂漂 閱讀(959) 評論(1)  編輯 收藏 引用 所屬分類: c#開發

            FeedBack:
            # re: 線程之間的通訊 UI 通訊 SynchronizationContext 使用 2010-12-28 15:03 lxf
            uiContext.Send(UpdateUI, "line " + i.ToString());
            參數不行吧??  回復  更多評論
              
            久久夜色精品国产欧美乱| 91精品国产综合久久香蕉 | 久久婷婷五月综合色奶水99啪 | 久久精品二区| 久久久久久久久久久精品尤物| 无码国内精品久久人妻蜜桃| 国产一区二区三区久久精品| 久久久久久国产精品免费免费| 久久久久久久精品成人热色戒| 国产精品久久久久久久久| 久久天天日天天操综合伊人av| 亚洲AV无码久久精品狠狠爱浪潮| segui久久国产精品| 美女久久久久久| 99久久er这里只有精品18| 伊人久久大香线蕉无码麻豆| 99久久99久久精品国产| 国内精品伊人久久久久777| 国产精品伦理久久久久久| 久久狠狠爱亚洲综合影院| 久久99精品久久久久久秒播| 久久精品国产亚洲AV麻豆网站 | 精品综合久久久久久97超人 | 超级97碰碰碰碰久久久久最新| 久久精品一区二区国产| 性做久久久久久久| 中文字幕久久精品无码| 午夜精品久久影院蜜桃| 精品久久久久久无码国产| 色综合久久久久| 69SEX久久精品国产麻豆| 久久国产热精品波多野结衣AV| 久久人人爽人人爽人人片AV高清 | 久久久精品人妻一区二区三区四| 大香伊人久久精品一区二区| 久久这里有精品视频| 久久精品国产99久久久香蕉| 久久av高潮av无码av喷吹| 久久久久97国产精华液好用吗| 久久se精品一区精品二区国产| 久久国产香蕉视频|