一直對invoke和begininvoke的使用和概念比較混亂,這兩天看了些資料,對這兩個的用法和原理有了些新的認識和理解。
首先說下,invoke和begininvoke的使用有兩種情況:
1. control中的invoke、begininvoke。
2. delegrate中的invoke、begininvoke。
這兩種情況是不同的,我們這裡要講的是第1種。下面我們在來說下.net中對invoke和begininvoke的官方定義。
control.invoke(引數delegate)方法:在擁有此控制項的基礎視窗控制代碼的執行緒上執行指定的委託。
根據這兩個概念我們大致理解invoke表是同步、begininvoke表示非同步。
如果你的後台執行緒在更新乙個ui控制項的狀態後不需要等待,而是要繼續往下處理,那麼你就應該使用begininvoke來進行非同步處理。
如果你的後台執行緒需要操作ui控制項,並且需要等到該操作執行完畢才能繼續執行,那麼你就應該使用invoke。
我們來做乙個測試。
invoke例子:
private void button1_click(objectsender, eventargs e)messagebox.show(thread.currentthread.gethashcode().tostring()+a);
} private voidstartmethod()
private voidinvokemethod()
結論:我們執行後,看下程式的執行順序,1aaa->3ccc和1bbb->1eee ->3ddd 。
解釋:主線程執行1aaa,然後1bbb和子執行緒3ccc同時執行,然後通過invoke來將invokemethod方法提交給主線程,然後子線 程等待主線程執行,直到主線程將invokemethod方法執行完成(期間必須等待主線程的任務執行完成,才會去執行invoke提交的任務),最後執 行子執行緒3ddd。
begininvoke例子:
private void button1_click(objectsender, eventargs e)messagebox.show(thread.currentthread.gethashcode().tostring()+a);
} private voidstartmethod()
private voidbegininvokemethod()
結論: 我們執行後看看執行的結果:1aaa->1bbb和3ccc->1eee和3ddd。
解釋: 主線程執行1aaa,然後1bbb和子執行緒3ccc同時執行,然後通過begininvoke來將invokemethod方法提交給主線程,然後主線程執行1eee(主線程自己的任務執行完成), 同時子執行緒繼續執行3ddd。
通過這個兩段**的測試比較,我們會發現其實invoke和begininvoke所提交的委託方法都是在主線程中執行的,其實根據我invoke 和begininvoke的定義我們要在子執行緒中來看這個問題,在invoke例子中我們會發現invoke所提交的委託方法執行完成後,才能繼續執行 ddd;在begininvoke例子中我們會發現begininvoke所提交的委託方法後,子執行緒講繼續執行ddd,不需要等待委託方法的完成。 那麼現在我們在回想下invoke(同步)和begininvoke(非同步)的概念,其實它們所說的意思是相對於子執行緒而言的,其實對於控制項的呼叫總是由 主線程來執行的。我們很多人搞不清這個同步和非同步,主要還是因為我們把參照物選錯了。其實有時候光看概念是很容易理解錯誤的。
正確的做法是將工作執行緒中涉及更新介面的**封裝為乙個方法,通過 invoke 或者 begininvoke
去呼叫,兩者的區別就是乙個導致工作執行緒等待,而另外乙個則不會。
而所謂的「一面響應操作,一面新增節點」永遠只能是相對的,使 ui 執行緒的負擔不至於太大而已,因為介面的正確更新始終要通過 ui
執行緒去做,我們要做的事情是在工作執行緒中包攬大部分的運算,而將對純粹的介面更新放到 ui 執行緒中去做,這樣也就達到了減輕 ui
using system.threading;
//啟動乙個執行緒
thread thread=new thread(new
threadstart(dowork));
thread.start();
//執行緒方法
private void dowork()
如果你像上面操作,在vs2005或2008裡是會有異常的...
正確的做法是用invoke\begininvoke
using system.threading;
namespace test
public void dowork());}
public void updateform(string param1,string parm2)
private void button1_click(object sender, eventargs e)}}
注意**的使用!
在 定會報出:從不是建立控制項的執行緒訪問它,這個異常。通常我們可以採用兩種方法來解決。一是通過設定control的屬性。二是通過delegate,而通
過delegate也有兩種方式,一種是常用的方式,另一種就是匿名方式。下面分別加以說明.
其次,通過delegate的方法來解決。
普通的委託方法例如:
delegate void safesettext(stringstrmsg);private void settext(stringstrmsg)
); }
else
}
delegate void safesettext(stringstrmsg);private void settext2(stringstrmsg)
textbox1.invoke(objset,new object);
}
這樣同樣可以實現。
個人覺得還是採用**好些。
在c# 3.0及以後的版本中有了lamda表示式,像上面這種匿名委託有了更簡潔的寫法。.net framework 3.5及以後版本更能用action封裝方法。例如以下寫法可以看上去非常簡潔:
void buttononclick(object sender,eventargs e)
this.invoke(new action(()=>
button.text="關閉";
最新:invoke(() =>
);
C 中Invoke的用法
在多執行緒程式設計中,我們經常要在工作執行緒中去更新介面顯示,而在多執行緒中直接呼叫介面控制項的方法是錯誤的做法,invoke 和 begininvoke 就是為了解決這個問題而出現的,使你在多執行緒中安全的更新介面顯示。正確的做法是將工作執行緒中涉及更新介面的 封裝為乙個方法,通過 invoke ...
C 中Invoke的用法
在用.net framework框架的winform構建gui程式介面時,如果要在控制項的事件響應函式中改變控制項的狀態,例如 某個按鈕上的文字原先叫 開啟 單擊之後按鈕上的文字顯示 關閉 初學者往往會想當然地這麼寫 void buttononclick object sender,eventarg...
C 中Invoke的用法()
一直對invoke和begininvoke的使用和概念比較混亂,這兩天看了些資料,對這兩個的用法和原理有了些新的認識和理解。首先說下,invoke和begininvoke的使用有兩種情況 1.control中的invoke begininvoke。2.delegrate中的invoke begini...