問題的產生:
我的winform程式中有乙個用於更新主視窗的工作執行緒(worker thread),但文件中卻提示我不能在多執行緒中呼叫這個form(為什麼?),而事實上我在呼叫時程式常常會崩掉。請問如何從多執行緒中呼叫form中的 方法呢?
解答:每乙個從control類中派生出來的winform類(包括control類)都是依靠底層 windows訊息和乙個訊息幫浦迴圈(message pump loop)來執行的。訊息迴圈都必須有乙個相對應的執行緒,因為傳送到乙個window的訊息實際上只會被傳送到建立該window的執行緒中去。其結果是, 即使提供了同步(synchronization),你也無法從多執行緒中呼叫這些處理訊息的方法。大多數plumbing是掩藏起來的,因為 winform是用**(delegate)將訊息繫結到事件處理方法中的。winform將windows訊息轉換為乙個基於**的事件,但你還是必須 注意,由於最初訊息迴圈的緣故,只有建立該form的執行緒才能呼叫其事件處理方法。如果你在你自己的執行緒中呼叫這些方法,則它們會在該執行緒中處理事件,而 不是在指定的執行緒中進行處理。你可以從任何執行緒中呼叫任何不屬於訊息處理的方法。
control類(及其派生類)實現了乙個定義在 system.componentmodel命名空間下的介面 -- isynchronizeinvoke,並以此來處理多執行緒中呼叫訊息處理方法的問題:
public inte***ce isynchronizeinvoke
form form;
/* obtain a reference to the form,
then: */
isynchronizeinvoke synchronizer;
synchronizer = form;
if(synchronizer.invokerequired)
else
form.close();
isynchronizeinvoke不僅僅用於winform中。例如,乙個calculator類提供了將兩個數字相加的add()方法,它就是通 過isynchronizeinvoke來實現的。使用者必須確定isynchronizeinvoke.invoke()方法的呼叫是執行在正確的執行緒中 的。
c# 在正確的執行緒中寫入呼叫
列表a. calculator類的add()方法用於將兩個數字相加。如果使用者直接呼叫add()方法,它會在該使用者的執行緒中執行呼叫,而使用者可以通過 isynchronizeinvoke.invoke()將呼叫寫入正確的執行緒中。
列表a:
public class calculator : isynchronizeinvoke
//isynchronizeinvoke implementation
public object invoke(delegate method,object args)
//client-side code
public delegate int adddelegate(int arg1,int arg2);
int threadid = thread.currentthread.gethashcode();
trace.writeline("client thread id is " + threadid.tostring());
calculator calc;
/* some code to initialize calc */
adddelegate adddelegate = new adddelegate(calc.add);
object arr = new object[2];
arr[0] = 3;
arr[1] = 4;
int sum = 0;
sum = (int) calc.invoke(adddelegate,arr);
debug.assert(sum ==7);
/* possible output:
calculator thread id is 29
client thread id is 30
*/或許你並不想進行同步呼叫,因為它被打包傳送到另乙個執行緒中去了。你可以通過begininvoke()和endinvoke()方法來實現 它。你可以依照通用的.net非同步程式設計模式(asynchronous programming model)來使用這些方法:用begininvoke()來傳送呼叫,用endinvoke()來實現等待或用於在完成時進行提示以及收集返回結果。
還值得一提的是isynchronizeinvoke方法並非安全型別。 型別不符會導致在執行時被丟擲異常,而不是編譯錯誤。所以在使用isynchronizeinvoke時要格外注意,因為編輯器無法檢查出執行錯誤。
實現isynchronizeinvoke要求你使用乙個**來在後期繫結(late binding)中動態地呼叫方法。每一種**型別均提供dynamicinvoke()方法: public object dynamicinvoke(object
args);
理論上來說,你必須將乙個方法**放到乙個需要提供物件執行的 真實的執行緒中去,並使invoke() 和begininvoke()方法中的**中呼叫dynamicinvoke()方法。isynchronizeinvoke的實現是乙個非同一般的程式設計 技巧,本文附帶的原始檔中包含了乙個名為synchronizer的幫助類(helper class)和乙個測試程式,這個測試程式是用來論證列表a中的calculator類是如何用synchronizer類來實現 isynchronizeinvoke的。synchronizer是isynchronizeinvoke的乙個普通實現,你可以使用它的派生類或者將 其本身作為乙個物件來使用,並將isynchronizeinvoke實現指派給它。
用來實現synchronizer的乙個重要 元素是使用乙個名為workerthread的巢狀類(nested class)。workerthread中有乙個工作專案(work item)查詢。workitem類中包含方法**和引數。invoke()和begininvoke()用來將乙個工作專案例項加入到查詢裡。 workerthread新建乙個.net worker執行緒,它負責監測工作專案的查詢任務。查詢到專案之後,worker會讀取它們,然後呼叫dynamicinvoke()方法。
C 多執行緒中呼叫python api函式
收藏今 天看了近一天關於多執行緒的應用中,如何安全呼叫python方面的資料,開始的時候看的簡直頭大如斗,被python語言的全域性鎖 global interpreter lock 執行緒狀態 thread state 等都有點繞暈了,後來經過各方面文章和幫助文件的相互參考,發現對於2.4 2.5...
C 在MFC中建立多執行緒
背景 在一台比較老的計算機上做的影象實時採集與繪製,同時還要顯示溫度場,單執行緒工作太卡 方案 afxbeginthread在mfc中不需要新增額外的標頭檔案 uint threadproc lpvoid lparam void cdemodlg kmeanssegment void cdemodl...
C 多執行緒中呼叫函式的方法
在多執行緒中呼叫函式的方法 以函式名和函式引數作為輸入物件來構造執行緒物件 t2 t4 t6 t7 通過lambda表示式呼叫函式,將函式作為lambda表示式的內容 t1 t3 t5 include include include void printall int a,int b,int c v...