我要實現的功能如下:
程序中有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
推薦這種做法,封裝一個事件,形如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的值發生改變,就激發一個事件,要自定義個事件
我也遇到類似問題,我的執行順序是
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(); } }