在非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()); } }