在非UI線程中調用MessageBox.Show()結果是非模態對話框;
在UI線程中調用MessageBox.Show()結果是模態對話框。
也就是說,MessageBox的模態仍是非模態控制的是它所在的那個線程!一旦使用MessageBox,它就阻塞了它所在的那個線程。編程
在非UI線程中調用System.Forms.Timer#Start方法無論用,在UI線程中才管用。網絡
以上兩個例子引出今日的主角:Control#Invoke()和Control#BeginInvoke()併發
在編程中,耗時的任務(好比IO,網絡請求等)是不容許放在UI線程中的。這一點在一切界面編程中老是成立的。在桌面編程中,從沒有庫明確禁止耗時任務放在UI線程中。你能夠把耗時的任務放在UI線程中,並無錯誤,只是難受的是本身。而Android中明確規定UI線程中禁止網絡請求,不然會拋出異常。
當耗時任務結束以後,一般須要更新界面,這時,Invoke和BeginInvoke這兩個函數就派上大用了。異步
this.Invoke(new Action(delegate{}));
string haha(string s) { return s + s.Length; } delegate string h(string s);//定義一個函數指針類型 Haha() { h ha = haha; IAsyncResult res = ha.BeginInvoke("weidiao", null, null); string ans = ha.EndInvoke(res);//此處會阻塞 Console.WriteLine(ans); }
IAsyncResult.IsCompleted屬性能夠判斷任務是否執行完畢。函數
IAsyncResult res = ha.BeginInvoke("weidiao", null, null); while (res.IsCompleted == false) { Console.Write("*"); Thread.Sleep(500); } string ans = ha.EndInvoke(res);
IAsyncResult.AsyncWaitHandle屬性可使當前線程(主調線程)等待一段時間。WaitOne的第一個參數表示要等待的毫秒數,在指定時間以內,WaitOne方法將一直等待,直到異步調用完成,併發出通知,WaitOne方法才返回true。當等待指定時間以後,異步調用仍未完成,WaitOne方法返回false,若是指定時間爲0,表示不等待,若是爲-1,表示永遠等待,直到異步調用完成。this
h ha = haha; IAsyncResult res = ha.BeginInvoke("weidiao", null, null); while (!res.AsyncWaitHandle.WaitOne(500)) { Console.Write("*"); } string ans = ha.EndInvoke(res); Console.WriteLine(ans);
使用回調函數線程
using System; using System.Threading; using System.Windows.Forms; class Haha { string haha(string s) { Thread.Sleep(3000); return s + s.Length; } delegate string h(string s); void callback(IAsyncResult res) { Console.Write(ha.EndInvoke(res)); } h ha ; Haha() { ha = haha; IAsyncResult res = ha.BeginInvoke("haha", new AsyncCallback(callback), null); } static void Main() { new Haha(); Application.Run(new Form()); } }