我要实现的功能以下:
程序中有2个线程,主线程和子线程,
主线程中有一个变量:X
主线程运行中激活子线程,子线程会作出计算改变 X 的值,
主线程继续作其它的事,直到 X 的值发生改变时,才会响应,并在textbox中输出 X 的值(这一过程当中主线程并不知道什么时候X的值才会变,它不能循环等待,必须去作别的事,好比接收用户点击等等)。
这个功能看起来简单,可是我始终找不到方法,我对委托和事件理解的还不透,不知道能不能用事件解决?
期待各位高手解答。web
autoresetevent 试试数组
将X封装成属性
在Set里写入须要触发的代码不就能够了?不必定要主线程去作,子线程固然也能够作的。多线程
你这也是委托的问题,参考一下:
app
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 是差很少的,区别本身看下msdnoop
推荐这种作法,封装一个事件,形如OnXChanged,主线程中注册此事件,事件触发时就会转到对应代码执行去了。
固然,此时还是在子线程中执行的。
如必定要主线程去作事,考虑使用信号量、WatiHandle等线程同步机制吧ui
赞成,实际上就是开放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();
}
|
很差意思,刚才有点错误
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的值发生改变,就激发一个事件,要自定义个事件
我也遇到相似问题,个人执行顺序是
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(); } }