c# Invoke和BeginInvoke

***************************************************

更多精彩,歡迎進入:http://shop115376623.taobao.com

***************************************************


轉自:http://blog.3snews.net/html/30/34530-27563.html

在多線程編程中,我們經常要在工作線程中去更新界面顯示,而在多線程中直接調用界面控件的方法 是錯誤的做法,Invoke 和 BeginInvoke 就是為了解決這個問題而出現的,使你在多線程中安全的更新界面顯示。

正確的做法是將工作線程中涉及更新界面的代碼封裝為一個方法,通過 Invoke 或者 BeginInvoke 去調用,兩者的區別就是一個導致工作線程等待,而另外一個則不會。

而所謂的“一面響應操作,一面添加節點”永遠只能是相對的,使 UI 線程的負擔不至于太大而已,因為界面的正確更新始終要通過 UI 線程去做,我們要做的事情是在工作線程中包攬大部分的運算,而將對純粹的界面更新放到 UI 線程中去做,這樣也就達到了減輕 UI 線程負擔的目的了。

舉個簡單例子說明下使用方法,比如你在啟動一個線程,在線程的方法中想更新窗體中的一個TextBox..?

using System.Threading;?

//啟動一個線程?
Thread thread=new Thread(new ThreadStart(DoWork));?
thread.Start();?

//線程方法?
private void DoWork()?
{?
this.TextBox1.Text="我是一個文本框";?
}?

如果你像上面操作,在VS2005或2008里是會有異常的...?

正確的做法是用Invoke\BeginInvoke

using System.Threading;
namespace test
{
public partial class Form1 : Form
{
public delegate void MyInvoke(string str1,string str2);
public Form1()
{
InitializeComponent();


}
public void DoWork()
{
MyInvoke mi = new MyInvoke(UpdateForm);
this.BeginInvoke(mi, new Object[] {"我是文本框","haha"});
}
public void UpdateForm(string param1,string parm2)
{
this.textBox1.Text = param1+parm2;
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
}
}
}

注意代理的使用!

//

c# Invoke和BeginInvoke 區別


轉自http://www.cnblogs.com/c2303191/articles/826571.html

Control.Invoke 方法 (Delegate)?:擁有此控件的基礎窗口句柄的線程上執行指定的委托。

Control.BeginInvoke 方法 (Delegate)?:在創建控件的基礎句柄所在線程上異步執行指定委托。

(一)Control的Invoke和BeginInvoke
我們要基于以下認識:
(1)Control的Invoke和BeginInvoke與Delegate的Invoke和BeginInvoke是不同的。
(2)Control的Invoke和BeginInvoke的參數為delegate,委托的方法是在Control的線程上執行的,也就是我們平時所說的UI線程。

我們以代碼(一)來看(Control的Invoke)
private delegate void InvokeDelegate();
private void InvokeMethod(){
???//C代碼段
}
private void butInvoke_Click(object sender, EventArgs e) {
???//A代碼段.......
???this.Invoke(new InvokeDelegate(InvokeMethod));
???//B代碼段......
}
你覺得代碼的執行順序是什么呢?記好Control的Invoke和BeginInvoke都執行在主線程即UI線程上
A------>C---------------->B
解釋:(1)A在UI線程上執行完后,開始Invoke,Invoke是同步
(2)代碼段B并不執行,而是立即在UI線程上執行InvokeMethod方法,即代碼段C。
(3)InvokeMethod方法執行完后,代碼段C才在UI線程上繼續執行。

看看代碼(二),Control的BeginInvoke
private delegate void BeginInvokeDelegate();
private void BeginInvokeMethod(){
???//C代碼段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
???//A代碼段.......
???this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));
???//B代碼段......
}

你覺得代碼的執行順序是什么呢?記好Control的Invoke和BeginInvoke都執行在主線程即UI線程上
A----------->B--------------->C慎重,這個只做參考。。。。。,我也不肯定執行順序,如果有哪位達人知道的話請告知。
解釋::(1)A在UI線程上執行完后,開始BeginInvoke,BeginInvoke是異步
(2)InvokeMethod方法,即代碼段C不會執行,而是立即在UI線程上執行代碼段B。
(3)代碼段B執行完后(就是說butBeginInvoke_Click方法執行完后),InvokeMethod方法,即代碼段C才在UI線程上繼續執行。

由此,我們知道:
Control的Invoke和BeginInvoke的委托方法是在主線程,即UI線程上執行的。也就是說如果你的委托方法用來取花費時間長的數據,然后更新界面什么的,千萬別在UI線程上調用Control.Invoke和Control.BeginInvoke,因為這些是依然阻塞UI線程的,造成界面的假死。

那么,這個異步到底是什么意思呢?

異步是指相對于調用BeginInvoke的線程異步,而不是相對于UI線程異步,你在UI線程上調用BeginInvoke ,當然不行了。----摘自"Invoke和BeginInvoke的真正涵義"一文中的評論。
BeginInvoke的原理是將調用的方法Marshal成消息,然后調用Win32 API中的RegisterWindowMessage()向UI窗口發送消息。----摘自"Invoke和BeginInvoke的真正涵義"一文中的評論。

(二)我們用Thread來調用BeginInvoke和Invoke
??????我們開一個線程,讓線程執行一些耗費時間的操作,然后再用Control.Invoke和Control.BeginInvoke回到用戶UI線程,執行界面更新。

代碼(三)? Thread調用Control的Invoke
private Thread invokeThread;
private delegate void invokeDelegate();
private void StartMethod(){
?? //C代碼段......
???Control.Invoke(new invokeDelegate(invokeMethod));
? //D代碼段......
}
private void invokeMethod(){
? //E代碼段
}
private void butInvoke_Click(object sender, EventArgs e) {
???//A代碼段.......
?? invokeThread = new Thread(new ThreadStart(StartMethod));
?? invokeThread.Start();
???//B代碼段......
}

你覺得代碼的執行順序是什么呢?記好Control的Invoke和BeginInvoke都執行在主線程即UI線程上
A------>(Start一開始B和StartMethod的C就同時執行)---->(C執行完了,不管B有沒有執行完,invokeThread把消息封送(invoke)給UI線程,然后自己等待)---->UI線程處理完butInvoke_Click消息后,處理invokeThread封送過來的消息,執行invokeMethod方法,即代碼段E,處理往后UI線程切換到invokeThread線程。
這個Control.Invoke是相對于invokeThread線程同步的,阻止了其運行。

解釋:
1。UI執行A
2。UI開線程InvokeThread,B和C同時執行,B執行在線程UI上,C執行在線程invokeThread上。
3。invokeThread封送消息給UI,然后自己等待,UI處理完消息后,處理invokeThread封送的消息,即代碼段E
4。UI執行完E后,轉到線程invokeThread上,invokeThread線程執行代碼段D

代碼(四)? Thread調用Control的BeginInvoke
private Thread beginInvokeThread;
private delegate void beginInvokeDelegate();
private void StartMethod(){
?? //C代碼段......
???Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));
? //D代碼段......
}
private void beginInvokeMethod(){
? //E代碼段
}
private void butBeginInvoke_Click(object sender, EventArgs e) {
???//A代碼段.......
?? beginInvokeThread = new Thread(new ThreadStart(StartMethod));
?? beginInvokeThread .Start();
???//B代碼段......
}
你覺得代碼的執行順序是什么呢?記好Control的Invoke和BeginInvoke都執行在主線程即UI線程上
A在UI線程上執行----->beginInvokeThread線程開始執行,UI繼續執行代碼段B,并發地invokeThread執行代碼段C-------------->不管UI有沒有執行完代碼段B,這時beginInvokeThread線程把消息封送給UI,單自己并不等待,繼續向下執行-------->UI處理完butBeginInvoke_Click消息后,處理beginInvokeThread線程封送過來的消息。


解釋:
1。UI執行A
2。UI開線程beginInvokeThread,B和C同時執行,B執行在線程UI上,C執行在線程beginInvokeThread上。
3。beginInvokeThread封送消息給UI,然后自己繼續執行代碼D,UI處理完消息后,處理invokeThread封送的消息,即代碼段E
有點疑問:如果UI先執行完畢,是不是有可能過了段時間beginInvokeThread才把消息封送給UI,然后UI才繼續執行封送的消息E。如圖淺綠的部分。


Control的BeginInvoke是相對于調用它的線程,即beginInvokeThread相對是異步的。
因此,我們可以想到。如果要異步取耗費長時間的數據,比如從數據庫中讀大量數據,我們應該這么做。
(1)如果你想阻止調用線程,那么調用代碼(三),代碼段D刪掉,C改為耗費長時間的操作,因為這個操作是在另外一個線程中做的。代碼段E改為更新界面的方法。
(2)如果你不想阻止調用線程,那么調用代碼(四),代碼段D刪掉,C改為耗費長時間的操作,因為這個操作是在另外一個線程中做的。代碼段E改為更新界面的方法。



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/459053.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/459053.shtml
英文地址,請注明出處:http://en.pswp.cn/news/459053.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Oracle手邊常用70則腳本知識匯總

Oracle手邊常用70則腳本知識匯總 作者:白寧超 時間:2016年3月4日13:58:36 摘要: 日常使用oracle數據庫過程中,常用腳本命令莫不是用戶和密碼、表空間、多表聯合、執行語句等常規操作。另外表的導入導出也很常用,這些腳步命令之前都…

php常見的面試題目

一. 基本知識點1.1 HTTP協議中幾個狀態碼的含義:503 500 401 403 404 200 301 302。。。200 : 請求成功,請求的數據隨之返回。301 : 永久性重定向。302 : 暫時行重定向。401 : 當前請求需要用戶驗證。403 : 服務器拒絕執行請求,即沒有權限。404 : 請求失…

php表示私有變量的是,PHP 訪問私有和受保護的成員變量

示例反射通常用作軟件測試的一部分,例如在運行時創建/實例化模擬對象。這對于在任何給定時間點檢查對象的狀態也非常有用。這是在單元測試中使用Reflection來驗證受保護的類成員是否包含期望值的示例。下面是一個非常基礎的汽車課。它具有受保護的成員變量&#xff…

BZOJ2683 簡單題(CDQ分治)

傳送門 之前聽別人說CDQ分治不難學,今天才知道果真如此。之前一直為自己想不到CDQ的方法二很不爽,今天終于是想出來了一道了,太弱…… cdq分治主要就是把整段區間分成兩半,然后用左區間的值去更新右區間的答案,每次把…

VS2010斷點設置技巧

*************************************************** 更多精彩,歡迎進入:http://shop115376623.taobao.com *************************************************** 許多Visual Studio下的程序員,甚至一些很有經驗的開發人員,都不…

IOS應用開發版本控制工具之Versions使用,iosversions

Versions版本控制工具破解版(Versions.zip)下載請見本博文附件。下載后在MAC安裝完以后,圖標是蓮花狀。見下圖: 雙擊運行如下圖: 點擊Repository,連接SVN服務器Repository(服務器端采用的是SVN服…

php form action跳轉,form表單頁面跳轉方式提交練習

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓//form表單提交練習/*新建一個form.html網頁用來書寫前端HTML表單*/表單提交練習姓名:年齡:電話:地址:QQ:自我評價://以上功能可自己添加或修改/*在form.html網頁的基礎上新建一個foms.php網頁關聯之前的form.html網頁并書寫php測試…

VS2010調試快捷鍵

*************************************************** 更多精彩,歡迎進入:http://shop115376623.taobao.com *************************************************** vs2010 調試快捷鍵 命令名 快捷鍵 說明 調試.應用代碼更改 Alt F10 啟動生…

什么是算法,什么是數據結構

盡管已經學了幾年,對它們也可以說大致懂得。但是,作為非計算機專業的人員,還是不會比計算機專業人員懂得多。既然沒有受過專門的學習訓練,自然會有三天打魚兩天曬網的感覺,一天可能冒出一個念頭。于是乎,寫…

如何在多web服務器共享SESSION數據

2019獨角獸企業重金招聘Python工程師標準>>> 一、問題起源 稍大一些的網站,通常都會有好幾個服務器,每個服務器運行著不同功能的模塊,使用不同的二級域名,而一個整體性強的網站,用戶系統是統一的&#xff0…

grpc php 返回值過大,使用grpc實現php、java、go三方互調

grpc作為經典的rpc協議,雖然略重,但是是有學習的價值的通過下面的內容可以快速上手這個grpc框架安裝命令行工具php需要這個額外的protoc、grpc_php_plugin工具把這個protobuf格式的文件生成php語言里的類go需要安裝protoc-gen-go工具把protobuf格式的接口…

SOCKET通信的基本步驟

SOCKET通信的基本步驟 1)建立一個服務器ServerSocket,并同時定義好ServerSocket的監聽端口;2)ServerSocket 調用accept()方法,使之處于阻塞。3)創建一個客戶機Socket,并設置好服務器的IP和端口。4&#xff…

Linux epoll 筆記(高并發事件處理機制)

wiki: Epoll優點; Epoll工作流程; Epoll實現機制: epollevent; Epoll源碼分析; Epoll接口: epoll_create; epoll_ctl; epoll_close; Epoll工作方式: LT(level-triggered); ET(edge-triggered); Epoll應用模式; Epoll優點&#xff…

Django請求響應對象

請求與響應對象 HttpRequest HttpRequest存儲了客戶請求的相關參數和一些查詢方法。 path請求頁面的全路徑,不包括域名—例如, "/hello/"。 methodHttp請求方法,包括GET,POST。 GETQueryDict類實例,包含所有HTTP GET參數的字典對象。 POSTQuer…

matlab 作圖 虛線太長,matlab?極坐標繪圖?在matlab中,用polar畫的圖形,如何使虛線圓多顯示幾個?...

滿意答案iredwood推薦于 2018.12.26采納率:52% 等級:12已幫助:13535人打開polar.m 文件,路徑可通過輸入 which polar 命令得到。其中修改下面這段代碼,可以控制虛線圓的顯示個數。其中rticks 為控制顯示個數的參量。…

《學習opencv》筆記——矩陣和圖像處理——cvAnd、cvAndS、cvAvg and cvAvgSdv

矩陣和圖像的操作 (1)cvAnd函數 其結構 void cvAnd( //將src1和src2按像素點取“位與運算”const CvArr* src1,//第一個矩陣const CvArr* src2,//第二個矩陣CvArr* dst,//結果矩陣const CvArr* mask NULL;//矩陣經行像素點與的“開關” );程序實例#include <cv.h> #inc…

Hibernate之加載策略(延遲加載與即時加載)和抓取策略(fetch)

假設現在有Book和Category兩張表,表的關系為雙向的一對多,表結構如下: 假設現在我想查詢id為2的那本書的書名,使用session.get(...)方法: 1 Session sessionHibernateUtil.getSession(); 2 Book book (Book) session.get(Book.class,2); 3 System.out.println(book.getName());…

指紋圖像方向圖matlab,matlab指紋方向場方向圖程序

function Fangxiangtu zhiwen_fangxiangtu( Zhiwentuxiang )%函數功能計算指紋方向圖%函數參數指紋圖像Zhiwentuxiang%函數返回值指紋方向圖FangxiangtuSizeZhiwentuxiang size( Zhiwentuxiang ) ;Zhiwentuxiang double( Zhiwentuxiang ) ;W 4; % 窗口大小(2W1)*(2W1)W 4;…

怎樣實現一個簡單的jQuery編程

第一步&#xff1a;在head中載入jQuery框架 <script  type"text/javascript" src"jQuery文檔所在的絕對路徑"></script> 注&#xff1a; type——指定腳本的mime類型 src——規定外部腳本文件的URL jQuery是一個javascript庫&#xff0c;相…

php多人點餐可以看到對方點的菜,千萬不要小看你身邊那個會點菜的人,因為

飯局上&#xff0c;你常常是負責點菜的那個人&#xff0c;還是只負責吃&#xff1f;拿起菜單點菜&#xff0c;你是很從容&#xff0c;還是不知道怎么點&#xff1f;事實上&#xff0c;飯局上那個會點菜的人&#xff0c;千萬不能小看。某次隨老板外出開會&#xff0c;跟去的幾個…