我要實現的功能以下:
程序中有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(); } }