首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

深入理解 WaitHandle.WaitAny:為何多個任務會同時執行?

     編輯:程式設計綜合問答

問題背景

在 MSDN 的範例程式碼中,使用 WaitHandle.WaitAny 等待多個非同步任務完成。開發者發現:即使 WaitAny 只會在「任一」訊號被觸發時返回,但兩個任務似乎都執行了。這引發了疑問:主執行緒不應該在第一個任務完成後立即繼續,而不等待第二個任務嗎?

核心原因分析

理論上 WaitAny 確實會在第一個訊號被設定(Set())時立即返回。但在實際執行環境中,存在以下因素導致「兩個任務都跑完」的現象:

  • 執行緒排程延遲:主執行緒在 WaitAny 返回後,可能不會立即獲得 CPU 時間片繼續執行;此期間,另一個工作執行緒可能已經完成工作並呼叫 Set()。
  • 單核心處理器:在單核環境下,執行緒切換更明顯,主執行緒被排程延遲的機率較高。
  • 機率性行為:這不是必然發生,而是取決於作業系統排程器的具體時機。若啟動大量執行緒(如 100 個),更容易觀察到此現象。

程式碼解析

Console.WriteLine("The main thread is waiting for either task to complete.");
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), waitHandles[0]);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), waitHandles[1]);
int index = WaitHandle.WaitAny(waitHandles); // 阻塞直到任一訊號觸發
Console.WriteLine("Task {0} finished first (time waited={1}).", index + 1, (DateTime.Now - dt).TotalMilliseconds);

static void DoTask(Object state) {
    AutoResetEvent are = (AutoResetEvent)state;
    int time = 1000 * r.Next(2, 10); // 2~9 秒隨機延遲
    Console.WriteLine("Performing a task for {0} milliseconds.", time);
    Thread.Sleep(time);
    are.Set(); // 通知完成
}

關鍵結論

WaitAny 保證的是「等待邏輯」在第一個訊號到達時解除阻塞,但不保證主執行緒會在同一瞬間搶回 CPU 繼續執行。因此,其他任務在主執行緒真正繼續前完成工作,是正常的並發行為,不代表 WaitAny 失效。

最佳實踐建議

  • 若需嚴格控制只執行最快任務並取消其餘任務,請配合 CancellationToken 實作協作式取消。
  • 理解「訊號觸發」與「執行緒實際繼續執行」之間存在的時間窗口,避免對時序做過強假設。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved