[英]Value getting changed in the iteration before the call begins
我的應用程序中包含以下代碼。
MyEventHandler handler = null; //Declare the handler
foreach (string pname in group)
{
handler = getHandler(pname); //Get the handler
if(handler == null)
{
throw new KeyNotFoundException("No user " + pname + " could be found");
}
//invoke the handler
handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
}
所以我得到處理程序並調用BeginInvoke
方法。 但是在調用BeginInvoke
之前,它將轉到下一次迭代,並且更改了處理程序的值。 因此, BeginInvoke
正在參與此新處理程序。
希望你明白我的意思。 那么我該如何消除這個問題呢? 我不想在BeginInvoke
之后打電話叫睡眠,因為我覺得這是浪費時間。
有任何想法嗎?
Update1我很確定在調用BeginInvoke()之前會更改處理程序對象。 我猜想BeginInvoke需要一些時間來創建一個單獨的線程來調用其他函數。
Update2此代碼在WCF服務中,並且客戶端調用一個函數,該函數進而使用此函數。 我為每個客戶端分別在服務器中存儲了處理程序。 WCF服務與客戶端具有單獨會話的雙工合同。 我看到執行此功能后,同一用戶被調用兩次。 但是我放了一個斷點並對其進行調試(這為BeginInvoke提供了調用該函數所需的時間),它可以“完美地”工作。 我非常確定我在線程中也遇到了這個問題,因為我在一個循環中創建了多個線程。 如果線程委托具有參數a,b,c,並且如果您在下一次迭代的開始對其進行更改,則會發生相同的行為。 我不知道你們中有多少人以前曾遇到過這個問題。 如果我放置一個Sleep(),或者如果我制作了處理程序的副本並使用copy調用它,它將起作用。
更新3
好的,我已經測試過了。 我只添加了Thread.Sleep()如下。
chatTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
Thread.Sleep(500);
它的運作就像一種魅力。 有什么想法嗎?
更新4
我創建了一個演示該問題的線程樣本,並將其上傳到此處 。 我希望對此的解決方案也能解決我的問題。 請檢查樣品。
好的,在您進行第四次編輯后,請提供一個示例,該示例肯定會出現問題,但您沒有尋求幫助的問題 。
您在問題中所說的是:
您在發布的代碼中展示的是:
這些不是同樣的問題!
您發布的代碼行為不當的原因是,相關代碼實際上看起來像這樣:
int i;
for (i = 0; i < 10; i++)
... create delegate, capture i, spawn thread
在這里,您正在為所有線程捕獲相同的變量。 如果線程在循環更改變量之前沒有開始執行,則可以,您將看到該變量的“錯誤值”。
但是,如果您像這樣更改代碼:
for (int i = 0; i < 10; i++)
{
int j = i;
ThreadStart threadStartObj = new ThreadStart(
delegate { PrintValueThreadFunction(j, j); });
^
|
+-- use j instead of i here
然后,您將為每個線程捕獲一個“新鮮”變量,該變量將保持不變。
因此,問題仍然存在。 這是您遇到的問題嗎? 如果是這樣,那么下次您 不要 羞辱您 , 不要簡化問題 。 您是在浪費別人的時間,大部分都是自己的。 如果您在幾分鍾內發布了上述代碼,那么您將在幾分鍾之內得到一個答案(或重復的問題,指向現有答案,那么多)。
如果這不是您遇到的問題,那么您仍然會遇到事件處理程序的問題,例如多次調用原始代碼中的事件處理程序,請返回並生成一個更好的示例項目。
我看不到為什么會發生這種情況-您發布的代碼可能無法重現您描述的行為。 完全合理的是,BeginInvoke調用可能不會立即實際執行任何操作,並且下一次迭代可能會在您實際看到該調用執行任何操作之前發生-因為它將被工作線程排隊等待處理。
這並不意味着將調用其他處理程序-調用BeginInvoke時將立即捕獲要調用的處理程序,因此本地變量隨后是否更改都無關緊要 。
另外-您為什么在這里有鎖? 除非多個線程在相同的可枚舉數上同時進行此處理(在這種情況下,您為什么要這樣做),否則我看不到您鎖定的任何原因。
我還要說的是,如果您根據調試器中看到的內容來判斷這種行為,那么您就不必擔心-通過這樣做以及混合使用多個線程,您將獲得調試器的“有趣”結果在“線程”調試器窗口中切換線程很重要。
問題是-您的程序實際上在做什么嗎? 如果是這樣,但是在調試時您會看到這種奇怪的行為-那完全是正常的。
正如一些評論所指出的那樣-您發布的代碼並不能完全解決問題。 例如,如果“處理程序”是在多個線程之間共享的局部變量,然后執行此迭代,那么可以,您將獲得類似的信息。 但是,方法本地的變量只能由該方法當前所在的同一線程修改(並確實讀取); 該規則的唯一例外是,然后將handler
引用作為ref
傳遞給另一個線程方法。
我認為您還有其他問題... handler.BeginInvoke在下一次迭代后無法調用,您仍然在同一線程中...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.