C#-线程-子线程如何通知主线程,个人总结

C# 子线程如何通知主线程,个人总结

我要实现的功能如下:
程序中有2个线程,主线程和子线程,
主线程中有一个变量:X
主线程运行中激活子线程,子线程会做出计算改变 X 的值,
主线程继续做其它的事,直到 X 的值发生改变时,才会响应,并在textbox中输出 X 的值(这一过程中主线程并不知道何时X的值才会变,它不能循环等待,必须去做别的事,比如接收用户点击等等)。

这个功能看起来简单,但是我始终找不到方法,我对委托和事件理解的还不透,不知道能不能用事件解决?
期待各位高手解答。


autoresetevent 试试


将X封装成属性

在Set里写入需要触发的代码不就可以了?不一定要主线程去做,子线程当然也可以做的。


你这也是委托的问题,参考一下:

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


 

引用 2 楼 tmxk2002 的回复:

将X封装成属性 

在Set里写入需要触发的代码不就可以了?不一定要主线程去做,子线程当然也可以做的。


推荐这种做法,封装一个事件,形如OnXChanged,主线程中注册此事件,事件触发时就会转到对应代码执行去了。

当然,此时仍是在子线程中执行的。

如一定要主线程去做事,考虑使用信号量、WatiHandle等线程同步机制吧


 

引用 5 楼 agentianle 的回复:

引用 2 楼 tmxk2002 的回复:
将X封装成属性 

在Set里写入需要触发的代码不就可以了?不一定要主线程去做,子线程当然也可以做的。 
 

推荐这种做法,封装一个事件,形如OnXChanged,主线程中注册此事件,事件触发时就会转到对应代码执行去了。 

当然,此时仍是在子线程中执行的。 

如一定要主线程去做事,考虑使用信号量、WatiHandle等线程同步机制吧

同意,实际上就是开放X的访问器。至于显示,简单点,还是不要让主线程去做的好。


楼上说的我大概明白,但是我要在textbox中输出 X 的值必须由主线程完成,也就是说主线程是一个窗口类,它才能完成显示输出的功能,子线程只负责计算。
4楼的代码:
  while (true) 
            { 
                if (myResetEvent.WaitOne()) 
                { 
                    Console.WriteLine("After child thread set X, X is " + X); 
                    myResetEvent.Reset(); 
                } 
            } 

这一段是否是要求主线程一直等待? 我的意思是主线程不能等待,还要去处理别的事,直到得到通知才去处理输出。


可以用自带的BackgroundWorker控件来实现 动态创建它


子线程可以操作界面的啊


用就 
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();

}

 


不好意思,刚才有点错误

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方法,顺利解决,部分代码如下:
 

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();
            }
        }

 

如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的关注我。(●'◡'●)

如果你觉得本篇文章对你有所帮助,请给予我更多的鼓励,求打             付款后有任何问题请给我留言!!!

因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【Jack_孟】!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值