c# 子線程如何通知主線程,我的總結

我要實現的功能以下:
程序中有2個線程,主線程和子線程,
主線程中有一個變量:X
主線程運行中激活子線程,子線程會作出計算改變 X 的值,
主線程繼續作其它的事,直到 X 的值發生改變時,纔會響應,並在textbox中輸出 X 的值(這一過程當中主線程並不知道什麼時候X的值纔會變,它不能循環等待,必須去作別的事,好比接收用戶點擊等等)。

這個功能看起來簡單,可是我始終找不到方法,我對委託和事件理解的還不透,不知道能不能用事件解決?
期待各位高手解答。web


autoresetevent 試試數組


將X封裝成屬性

在Set裏寫入須要觸發的代碼不就能夠了?不必定要主線程去作,子線程固然也能夠作的。
多線程


你這也是委託的問題,參考一下:
app

C# code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private  void  button1_Click( object  sender, EventArgs e)
{
     Thread th =  new  Thread(aa);
     th.Start();
}
 
delegate  void  somedle();
private  void  aa()
{
     if  ( this .InvokeRequired)
     {
         somedle sd =  new  somedle(aa);
         this .Invoke(sd);
         return ;
     }
     ShowChar( 'A' );
}
public  void  ShowChar( char  ch)
{
     lock  ( this )
     {
         textBox1.Text += ch;
     }
}

 


  static void Main(string[] args)
        {
            ManualResetEvent myResetEvent = new ManualResetEvent(false);

            int X = 0;

            Thread childThread = new Thread(delegate()
            {
                //Console.WriteLine(Thread.CurrentThread.Name + "  " + Thread.CurrentThread.ManagedThreadId);

                Console.WriteLine("Set X Value");
                X = 10;
                Console.WriteLine("Set X Value end");

                Console.WriteLine("Notice main thread");
                myResetEvent.Set();
            });

            childThread.Start();

            while (true)
            {
                if (myResetEvent.WaitOne())
                {
                    Console.WriteLine("After child thread set X, X is " + X);
                    myResetEvent.Reset();
                }
            }

            Console.ReadKey();
        }

這裏主要是ManualResetEvent的應用,和前面的兄弟提到的autoresetevent 是差很少的,區別本身看下msdn
oop


 

引用 2 樓 tmxk2002 的回覆:
將X封裝成屬性 

在Set裏寫入須要觸發的代碼不就能夠了?不必定要主線程去作,子線程固然也能夠作的。


推薦這種作法,封裝一個事件,形如OnXChanged,主線程中註冊此事件,事件觸發時就會轉到對應代碼執行去了。

固然,此時還是在子線程中執行的。

如必定要主線程去作事,考慮使用信號量、WatiHandle等線程同步機制吧
ui


 

引用 5 樓 agentianle 的回覆:
引用 2 樓 tmxk2002 的回覆:
將X封裝成屬性 

在Set裏寫入須要觸發的代碼不就能夠了?不必定要主線程去作,子線程固然也能夠作的。 
 

推薦這種作法,封裝一個事件,形如OnXChanged,主線程中註冊此事件,事件觸發時就會轉到對應代碼執行去了。 

固然,此時還是在子線程中執行的。 

如必定要主線程去作事,考慮使用信號量、WatiHandle等線程同步機制吧

贊成,實際上就是開放X的訪問器。至於顯示,簡單點,仍是不要讓主線程去作的好。this


樓上說的我大概明白,可是我要在textbox中輸出 X 的值必須由主線程完成,也就是說主線程是一個窗口類,它才能完成顯示輸出的功能,子線程只負責計算。
4樓的代碼:
  while (true) 
            { 
                if (myResetEvent.WaitOne()) 
                { 
                    Console.WriteLine("After child thread set X, X is " + X); 
                    myResetEvent.Reset(); 
                } 
            } 

這一段是不是要求主線程一直等待? 個人意思是主線程不能等待,還要去處理別的事,直到獲得通知纔去處理輸出。
url


能夠用自帶的BackgroundWorker控件來實現 動態建立它spa


子線程能夠操做界面的啊.net


用就 
Form.Invoke(Delegae d);
這個方法就能夠,你在子線程中改變檢查到某個值時候通知主線程就能夠了
讓改變發生在 參數d所指向的那個方法中就能夠了;


 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  delegate  void  SetIntValue( int  value);
 
public  void  setX( int  value)
{
     if  (InvokeRequired)
     {
         // 在子線程中調用此方法時,經過Invoke轉成主線程執行
         Invoke( new  SetIntValue(value));
         return ;
     }
 
     // 設置X值並顯示
     X = value;
     textbox.Text = X.toString();
}

 


很差意思,剛纔有點錯誤

C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  delegate  void  SetIntValue( int  value);
 
public  void  setX( int  value)
{
     if  (InvokeRequired)
     {
         // 在子線程中調用此方法時,經過Invoke轉成主線程執行
         <span style= "color: #FF0000;" >Invoke( new  SetIntValue(setX), value);</span>
         return ;
     }
 
     // 設置X值並顯示
     X = value;
     textbox.Text = X.toString();
}

 


開啓一個新的線程就好了,只要X的值發生改變,就激發一個事件,要自定義個事件


 

引用 10 樓 projectdd 的回覆:
用就 
Form.Invoke(Delegae d);
這個方法就能夠,你在子線程中改變檢查到某個值時候通知主線程就能夠了
讓改變發生在 參數d所指向的那個方法中就能夠了;

我也遇到相似問題,個人執行順序是
1.主線程 建立一個窗體mForm對象並Show();
2.開啓一個新的子線程,子線程指向循環方法DoFor(),控制mForm中的TextBox.Text顯示;
3.當循環完畢後,我想關閉Close()由主線程建立的mForm,這時和樓主相似的問題出現了,我但願在子線程循環方法DoFor()中的for()循環結束後加上 mForm.Close();但這裏會提示mForm不是當前線程建立的對象,因而採用invoke方法,順利解決,部分代碼以下:

C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
         myForm mForm=  null ; //myForm是以前定義的一個窗體類
         private  delegate  void  OnClose(); //定義委託
         //省略其餘代碼。。。
          //主線程按鈕點擊事件
         private  void  button1_Click( object  sender, EventArgs e)
         {
             //建立彈出窗體
             mForm=  new  myForm ( true , 1, 100, ProgressBarStyle.Continuous);
             mForm.Show();
             //新線程
             Thread mThread =  new  Thread( new  ThreadStart(DoFor));
             mThread.Start();  
         }
         private  void  DoFor()
        
             for  ( int  i = 1; i <= 100; i++)
             {
                 System.Threading.Thread.Sleep(10);
                 mForm.OnSetValue(i); //這裏改變彈出窗口的一個TextBox的Text屬性
             }
             //循環結束後
             this .Invoke( new  OnClose(DoClose)); //子線程中關閉主線程建立的對象
 
         }
         //委託指向的方法
         private  void  DoClose()
         {
             mForm.Close();
         }
     }

但願對你有幫助!


出處:http://bbs.csdn.net/topics/300091034

==

本身總結子線程通知主線程,代碼以下:

        private void updateUI(string s)
        {
            textBox1.Text += s;
        }

        public delegate void SetValueHandler(string value);

        private void doWork()
        {
            string val = "good\r\n";
            if (this.textBox1.InvokeRequired)
            {
                // 在子線程中調用此方法時,經過Invoke轉成主線程執行
                //this.textBox1.Invoke(new SetValueHandler(updateUI), val);  //方式一:經過代理建立的方法更新界面
                this.Invoke(new EventHandler(delegate { textBox1.Text += val; }));  //方式二:使用匿名代理來更新界面
                return;
            }
            // 設置X值並顯示
            textBox1.Text += val.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            tm.Start();
        }

上面的代碼是窗體應用程序,子線程更新主線程,使用方式一和方式二均可以實現。

再給個WPF程序的子線程更新主線程的代碼:

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(updateWork));
            t.Start();
        }

        delegate void updateUIHandler(double[] a);

        private void updateWork()
        {
            double[] _tt;

            updateUIHandler mothed = new updateUIHandler(updateUI);
            while (true)
            {
                _tt = GetValue();  //用於獲取一個數組
                //this.Dispatcher.Invoke(mothed, _t); //方式一::經過代理建立的方法更新界面中的數據
                base.Dispatcher.BeginInvoke(new Action(delegate { for (int i = 0; i < _tt.Length; i++) { _lindData.Append(_tt[i]); } }));//方式二:使用匿名代理來更新界面中的數據
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5));
            }
        }

        private void updateUI(double[] _t)
        {
            for (int i = 0; i < _t.Length; i++)
            {
                _lindData.Append(_t[i]);
            }
        }

在wpf程序中須要使用this.Dispatcher.Invoke或者base.Dispatcher.BeginInvoke方法進行主線程數據的更新。

以上程序僅供你們參考。

在寫一個方式:

//在多線程執行的方法中,調用執行 : ShowFormAsyn(f, fName);

        private void ShowFormAsyn(Form f, string fName)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(delegate { ShowFormAsyn(f, fName); }));
            }
            else
            {
                f.MdiParent = this;
                f.Parent = subpanel3;
                f.Show();
            }
        }
相關文章
相關標籤/搜索