簡體   English   中英

值在調用開始之前的迭代中被更改

[英]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

我創建了一個演示該問題的線程樣本,並將其上傳到此處 我希望對此的解決方案也能解決我的問題。 請檢查樣品。

好的,在您進行第四次編輯后,請提供一個示例,該示例肯定會出現問題,但沒有尋求幫助的問題

您在問題中所說的是:

  • 我在委托變量上使用BeginInvoke,然后更改該變量,並以某種方式調用我的委托兩次

您在發布的代碼中展示的是:

  • 我在匿名方法中捕獲了循環變量,並且以某種方式使用了錯誤的變量值

這些不是同樣的問題!

您發布的代碼行為不當的原因是,相關代碼實際上看起來像這樣:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM