Invoke 和 BeginInvoke 的區別

2021-05-24 10:41:13 字數 3109 閱讀 8571

討論環境:c# 、.net、vs2005

.net預設所有的可視窗體在主線程內維護,如果某工作執行緒(主線程之外)想實現對窗體控制項的操作,預設情況下是不允許直接操作的,而要通過 invoke 方法將其封送到主線程去完成。在control 類內提供了 invoke 和 begininvoke 兩個方法實現該功能,msdn 幫助中提到,它們的唯一區別是 begininvoke 多了「非同步執行」四個字。(兩方法的具體幫助請自行檢視msdn,這裡不多羅嗦了)。

「非同步執行」怎麼理解,查了網上的一些解答,通過reflector檢視了兩方法的背後原始碼後,得出如下結論:

invoke引起工作執行緒的阻塞,begininvoke不引起工作執行緒的阻塞。

具體解釋一下:我們先假設稱主線程(即窗體控制項的擁有者)為a執行緒,工作執行緒為b執行緒,如果b執行緒需要操作窗體控制項,那麼就要使用invoke(或begininvoke),將相應的操作通過**,封送到主線程a(具體的**實現,不多羅嗦,假設讀者已知)。那麼.net背後是怎麼實現執行緒間「任務挪移」這一步操作的呢?通過reflector檢視原始碼後發現,原來 invoke 將你交給它的委託封裝成了乙個標準的windows訊息,加進了主線程的訊息佇列內。回到invoke 和 begininvoke 的區別上來,如果使用 invoke,那麼 b 執行緒必須等到a執行緒響應了傳送的訊息後 才能得到返回值,而如果使用begininvoke,則b執行緒將訊息送到a執行緒後,馬上返回,並不一定等待該訊息被a執行緒響應完成。所以如果a執行緒處在繁忙狀態或休眠狀態,使用 invoke 封送訊息就會使得b執行緒被堵塞,而是用 begininvoke 則不然,這就是所謂的「非同步執行」了。

空口無憑,讓我們來看看invoke和 begininvoke 背後的**:

public objectinvoke(delegate method, params object args)
}
public iasyncresultbegininvoke(delegate method, params object args)
}
兩方法對應的**基本一樣,除了返回型別外,還有一處細微的差別 marshaledinvoke 方法的第三個引數:invoke 為 true,begininvoke 為 false。這個引數表示什麼意思呢?把marshaledinvoke 背後的**拉出來看看:

private objectmarshaledinvoke(control caller, delegate method, object args, bool synchronous)
if (((activeximpl) this.properties.getobject(propactiveximpl)) != null)
boolflag= false;
if ((safenativemethods.getwindowthreadprocessid(new handleref(this, this.handle), out num) == safenativemethods.getcurrentthreadid()) && synchronous)
executioncontextexecutioncontext= null;
if (!flag)
threadmethodentryentry= new threadmethodentry(caller, method, args, synchronous, executioncontext);
lock (this)
}
lock (this.threadcallbacklist)
this.threadcallbacklist.enqueue(entry);
}
if (flag)
else
if (!synchronous)
if (!entry.iscompleted)
if (entry.exception != null)
return entry.retval;
好長的一段**,看著都眼暈。看看剛才提到的第三個引數的名字 synchronous ,從字面意思看『是否同步』,ok,再看看最後被加粗的幾行**(還是根據字面意思猜):如果不同步,立刻返回;如果同步,而且沒完事,就等一等,最後給出返回值。如果我們的假設成立,那麼 invoke 方法的第三個引數為true,就是要同步;begininvoke 方法的第三個引數為 false,就是不同步,即非同步。right,到這裡就和 msdn 幫助上介紹 begininvoke 「非同步執行」就對上了。

如果按照數學分析歸納法,到此應該說:由以上分析,得證:

invoke引起工作執行緒的阻塞,begininvoke不引起工作執行緒的阻塞。system.windows.forms.control.checkforillegalcrossthreadcalls = false;

第二,既然begininvoke不引起阻塞,那麼是否就說明它比 invoke 好呢。我在自己的程式裡,把所有的 invoke 均變成 begininvoke ,執行一段時間後,結果提示 stackoverflowexception 錯誤,幫助對這個異常的說明是「掛起的方法呼叫過多而導致執行堆疊溢位時引發的異常」。看來還是要慎用。

生活***需要激情,做事需冷靜,說話需冷靜!

遇事記著:辦法總比困難多,困難和問題說不定就是機遇和轉折!

歷史證明:哪個環節沒照顧到,哪個環節就會出問題!能自己來,就不要讓別人來。

我理解的invoke和begininvoke

一直對invoke和begininvoke的使用和概念比較混亂,這兩天看了些資料,對這兩個的用法和原理有了些新的認識和理解。首先說下,invoke和begininvoke的使用有兩種情況 1.control中的invoke begininvoke。2.delegrate中的invoke begini...

php魔術方法 invoke

php5.3新增了乙個叫做 invoke的魔術方法,這樣在建立例項後,可以直接呼叫物件。就是用函式的方式來用物件,比如我現在有個a類,如果我想防止別人直接輸出物件,那麼我可以這樣 class a a new a echo a 那麼就會輸出 不允許這樣使用 invoke 方法,也可以,帶引數 clas...

方法呼叫指令invoke

1 方法呼叫 分派 執行過程 jvm呼叫方法有五條指令,分別是 1 invokestatic,用來呼叫static方法 類方法 2 invokespecial,用來呼叫需要特殊處理的例項方法,私有方法,父類方法 super.初始化方法。在物件的建立過程中,new之後很多都會執行方法,就是依賴位元組碼...