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

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


autoresetevent 试试


将X封装成属性

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


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

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


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

不好意思,刚才有点错误

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

==

自己总结子线程通知主线程,代码如下:

  1. private void updateUI(string s)
  2. {
  3. textBox1.Text += s;
  4. }
  5.  
  6. public delegate void SetValueHandler(string value);
  7.  
  8. private void doWork()
  9. {
  10. string val = "good\r\n";
  11. if (this.textBox1.InvokeRequired)
  12. {
  13. // 在子线程中调用此方法时,通过Invoke转成主线程执行
  14. //this.textBox1.Invoke(new SetValueHandler(updateUI), val); //方式一:通过代理创建的方法更新界面
  15. this.Invoke(new EventHandler(delegate { textBox1.Text += val; })); //方式二:使用匿名代理来更新界面
  16. return;
  17. }
  18. // 设置X值并显示
  19. textBox1.Text += val.ToString();
  20. }
  21.  
  22. private void button1_Click(object sender, EventArgs e)
  23. {
  24. tm.Start();
  25. }

上面的代码是窗体应用程序,子线程更新主线程,使用方式一和方式二都可以实现。

再给个WPF程序的子线程更新主线程的代码:

  1. private void button2_Click(object sender, RoutedEventArgs e)
  2. {
  3. System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(updateWork));
  4. t.Start();
  5. }
  6.  
  7. delegate void updateUIHandler(double[] a);
  8.  
  9. private void updateWork()
  10. {
  11. double[] _tt;
  12.  
  13. updateUIHandler mothed = new updateUIHandler(updateUI);
  14. while (true)
  15. {
  16. _tt = GetValue(); //用于获取一个数组
  17. //this.Dispatcher.Invoke(mothed, _t); //方式一::通过代理创建的方法更新界面中的数据
  18. base.Dispatcher.BeginInvoke(new Action(delegate { for (int i = ; i < _tt.Length; i++) { _lindData.Append(_tt[i]); } }));//方式二:使用匿名代理来更新界面中的数据
  19. System.Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5));
  20. }
  21. }
  22.  
  23. private void updateUI(double[] _t)
  24. {
  25. for (int i = ; i < _t.Length; i++)
  26. {
  27. _lindData.Append(_t[i]);
  28. }
  29. }

在wpf程序中需要使用this.Dispatcher.Invoke或者base.Dispatcher.BeginInvoke方法进行主线程数据的更新。

以上程序仅供大家参考。

在写一个方式:

  1. //在多线程执行的方法中,调用执行 : ShowFormAsyn(f, fName);
  2.  
  3. private void ShowFormAsyn(Form f, string fName)
  4. {
  5. if (this.InvokeRequired)
  6. {
  7. this.Invoke(new EventHandler(delegate { ShowFormAsyn(f, fName); }));
  8. }
  9. else
  10. {
  11. f.MdiParent = this;
  12. f.Parent = subpanel3;
  13. f.Show();
  14. }
  15. }

c# 子线程如何通知主线程,个人总结的更多相关文章

  1. C#子线程执行完后通知主线程

    其实这个比较简单,子线程怎么通知主线程,就是让子线程做完了自己的事儿就去干主线程的转回去干主线程的事儿. 那么怎么让子线程去做主线程的事儿呢,我们只需要把主线程的方法传递给子线程就行了,那么传递方法就 ...

  2. c#子线程执行完怎么通知主线程

    定义一个委托实现回调函数 public delegate void CallBackDelegate(string message); 程序开始的时候 //把回调的方法给委托变量 CallBackDe ...

  3. android的子线程切换到主线程

    在子线程中,如果想更新UI,必须切换到主线程,方法如下: if (Looper.myLooper() != Looper.getMainLooper()) { // If we finish mark ...

  4. C#子线程中更新主线程UI-----注意项

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...

  5. main函数是主线程吗

    1.线程的概念: 线程是程序最基本的运行单位,而进程不能运行,所以能运行的,是进程中的线程. 2.线程是如何创建起来的: 进程仅仅是一个容器,包含了线程运行中所需要的数据结构等信息.一个进程创建时,操 ...

  6. Android判断当前是否在主线程

    Android开发中, 有时需要判断当前线程到底是主线程, 还是子线程, 例如: 我们在自定义View时, 想要让View重绘, 需要先判断当前线程到底是不是主线程, 然后根据判断结果来决定到底是调用 ...

  7. Java知多少(57)主线程

    当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread),因为它是程序开始时就执行的.主线程的重要性体现在两方面: 它是产生其他子线程的线程: 通常它必须最后完成执 ...

  8. Java多线程系列--“基础篇”10之 线程优先级和守护线程

    概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...

  9. Java多线程(十)——线程优先级和守护线程

    一.线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5.“高优先级线程”会优先于“低优先级线程”执行. java 中有两种线程:用户线程和守护线程.可以通过isDaemon( ...

随机推荐

  1. ng-深度学习-课程笔记-2: 神经网络中的逻辑回归(Week2)

    1 二分类( Binary Classification ) 逻辑回归是一个二分类算法.下面是一个二分类的例子,输入一张图片,判断是不是猫. 输入x是64*64*3的像素矩阵,n或者nx代表特征x的数 ...

  2. jmeter命令行运行与生成报告

    一.     使用命令行方式运行Jmeter 1.1 为什么 使用GUI方式启动jmeter,运行线程较多的测试时,会造成内存和CPU的大量消耗,导致客户机卡死. 所以正确的打开方式是在GUI模式下调 ...

  3. U盘安装window系统

    U盘安装window系统: 1. 制作系统启动U盘,推荐使用老毛桃. 2. 电脑上插入U盘,启动系统,选择U盘启动. 3. 进入老毛桃选择界面,选择生成PE系统.推荐win8,之前在一个戴尔电脑上使用 ...

  4. C++虚函数分析

    1.虚函数(impure virtual) c++虚函数主要是提供“运行时多态”,父类提供虚函数的默认实现,子类可以虚函数进行重写. 2.纯虚函数(pure virtual)       c++纯虚函 ...

  5. pyDay8

    内容来自廖雪峰的官方网站. List Comprehensions 1 >>> list(range(1, 3)) [1, 2] 2 >>> L = [] > ...

  6. Python 3 并发编程多进程之进程池与回调函数

    Python 3 进程池与回调函数 一.进程池 在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间.多进程是实现并发的手段之一,需要注意 ...

  7. C++中的动态绑定

    C++中基类和派生类遵循类型兼容原则:即可用派生类的对象去初始化基类的对象,可用派生类的对象去初始化基类的引用,可用派生类对象的地址去初始化基类对象指针. C++中动态绑定条件发生需要满足2个条件: ...

  8. 读underscore

    最近在拜读只有1700行(含注释)代码的Underscore.js 1.9.1,记录一些东西 (参考https://underscorejs.org/underscore.js,https://git ...

  9. 2018-2019-2《网络对抗技术》Exp0 Kali安装 Week1

    2018-2019-2<网络对抗技术>Exp0 Kali安装 Week1 Kali的安装 设置虚拟机的名称和操作系统 为虚拟机分配虚拟内存,大小为4096M,分配存储空间,大小为25.0G ...

  10. DBMS_LOB的简单用法以及释放DBMS_LOB生成的临时CLOB内存

    dbms_lob包(一) dbms_lob包(二) 如何释放DBMS_LOB.CREATETEMPORARY的空间 Temporary LOB导致临时表空间暴满. oracle数据库中的大对象1——永 ...