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 = ; i < _tt.Length; i++) { _lindData.Append(_tt[i]); } }));//方式二:使用匿名代理来更新界面中的数据
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5));
}
} private void updateUI(double[] _t)
{
for (int i = ; 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();
}
}
c# 子线程如何通知主线程,个人总结的更多相关文章
- C#子线程执行完后通知主线程
其实这个比较简单,子线程怎么通知主线程,就是让子线程做完了自己的事儿就去干主线程的转回去干主线程的事儿. 那么怎么让子线程去做主线程的事儿呢,我们只需要把主线程的方法传递给子线程就行了,那么传递方法就 ...
- c#子线程执行完怎么通知主线程
定义一个委托实现回调函数 public delegate void CallBackDelegate(string message); 程序开始的时候 //把回调的方法给委托变量 CallBackDe ...
- android的子线程切换到主线程
在子线程中,如果想更新UI,必须切换到主线程,方法如下: if (Looper.myLooper() != Looper.getMainLooper()) { // If we finish mark ...
- C#子线程中更新主线程UI-----注意项
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- main函数是主线程吗
1.线程的概念: 线程是程序最基本的运行单位,而进程不能运行,所以能运行的,是进程中的线程. 2.线程是如何创建起来的: 进程仅仅是一个容器,包含了线程运行中所需要的数据结构等信息.一个进程创建时,操 ...
- Android判断当前是否在主线程
Android开发中, 有时需要判断当前线程到底是主线程, 还是子线程, 例如: 我们在自定义View时, 想要让View重绘, 需要先判断当前线程到底是不是主线程, 然后根据判断结果来决定到底是调用 ...
- Java知多少(57)主线程
当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread),因为它是程序开始时就执行的.主线程的重要性体现在两方面: 它是产生其他子线程的线程: 通常它必须最后完成执 ...
- Java多线程系列--“基础篇”10之 线程优先级和守护线程
概要 本章,会对守护线程和线程优先级进行介绍.涉及到的内容包括:1. 线程优先级的介绍2. 线程优先级的示例3. 守护线程的示例 转载请注明出处:http://www.cnblogs.com/skyw ...
- Java多线程(十)——线程优先级和守护线程
一.线程优先级的介绍 java 中的线程优先级的范围是1-10,默认的优先级是5.“高优先级线程”会优先于“低优先级线程”执行. java 中有两种线程:用户线程和守护线程.可以通过isDaemon( ...
随机推荐
- android,结合Timer和TimerTask实现定时任务
当我们需要每隔一段时间执行一个任务的时候,就需要使用TimerTask了,下面是入门的例子, 值得注意的是Timer.TimerTask,cancel之后就需要重新声明一个对象,否则会报错的哦~ pa ...
- CentOS下 Nginx1.13.5 + PHP7.1.10 + MySQL5.7.19 源码编译安装
一.安装Nginx ①安装依赖扩展 # yum -y install wget openssl* gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng l ...
- Python3.x获取网页源码
Python3.x获取网页源码 1,获取网页的头部信息以确定网页的编码方式: import urllib.request res = urllib.request.urlopen('http://ww ...
- 20145325张梓靖 《Java程序设计》第7周学习总结
20145325张梓靖 <Java程序设计>第7周学习总结 教材学习内容总结 时间的度量 格林威治时间,简称GMT时间,由观察太阳而得来:世界时,UT:国际原子时,TAI:世界协调时间,U ...
- mysql的隔离性和锁
INNODB的隔离性质 INNODB的事务支持4种隔离机制,分别是 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABL ...
- SharePoint研究之表单登录配置
本文将演示SharePoint怎样配置表单(Form)登录,后续文章将研究 无密码登录.编程添加用户组.编程添加用户.编程添加文件夹.编程分享文件夹(权限分配)等. 知识点:SharePoint.Sq ...
- OpenDayLight Helium安装
参照:OpenDaylight的Helium(氦)版本安装 下载链接地址为 http://www.opendaylight.org/software/downloads/helium 安装: unzi ...
- AI病毒来袭,拿什么拯救你我的电脑?
文|雷宇 来源|智能相对论(aixdlun) 在刘慈欣的科幻小说<中国2185>中,除领土,领海,领空外,还有一个被称为电子领土的地方,这个地方除了容易受常规武器破坏外,还容易受到软件武器 ...
- bzoj2463: [中山市选2009]谁能赢呢? 博弈
小明和小红经常玩一个博弈游戏.给定一个n×n的棋盘,一个石头被放在棋盘的左上角.他们轮流移动石头.每一回合,选手只能把石头向上,下,左,右四个方向移动一格,并且要求移动到的格子之前不能被访问过.谁不能 ...
- 高并发数据采集的架构应用(Redis的应用)
问题的出发点: 最近公司为了发展需要,要扩大对用户的信息采集,每个用户的采集量估计约3W.如果用户量增加的话,将会大量照成采集量成3W倍的增长,但是又要满足日常业务需要,特别是报表数据必要 ...