2010-08-24 144 views
2

我使用新的Parallel.For工作,創建多個線程來執行相同的操作。使所有線程睡眠

如果其中一個線程失敗,這意味着我工作「太快」,我需要把所有的線程休息幾秒鐘。

有沒有辦法執行像Thread.Sleep之類的東西 - 只對所有線程同時執行相同的操作?

+0

如果你睡在所有的線程上,不會等待你沒有完成的那個?您至少需要1個正在運行的線程。 – leppie 2010-08-24 04:58:30

+0

不,線程在我的電腦上執行操作,需要電腦「冷靜下來」。第一個線程將在幾秒鐘後重新嘗試。 (希望你明白)不需要運行線程。最後,線程會寫出他失敗 - 我只是不想讓所有線程寫入失敗,但要學習原始線程的錯誤並等待。 (Geez ..這是一個笨拙的解釋) – Faruz 2010-08-24 05:04:23

+0

你可以在每個動作結束時檢查一個變量,並使任何線程睡眠的值的數量存在。是否有意義? – leppie 2010-08-24 05:08:51

回答

2

除了Parallel.For位之外,這是對問題的直接回答。 這確實是一個可怕的模式;你可能應該使用適當的同步機制,並且讓工作線程在不搶佔的情況下偶爾檢查是否需要「退出」。 此外,這款採用Thread.SuspendThread.Resume這兩者都是過時,有很好的理由(從Thread.Suspend):

「不要使用掛起和恢復方法的線程活動同步你沒有辦法知道什麼如果在安全權限評估過程中掛起一個線程的同時鎖定了某個線程,AppDomain中的其他線程可能被阻塞,如果在執行某個類構造函數時掛起線程,嘗試使用該類的AppDomain被阻止,死鎖很容易發生。「

(未經測試)

public class Worker 
{ 
    private readonly Thread[] _threads; 
    private readonly object _locker = new object(); 
    private readonly TimeSpan _tooFastSuspensionSpan; 
    private DateTime _lastSuspensionTime; 

    public Worker(int numThreads, TimeSpan tooFastSuspensionSpan) 
    { 
     _tooFastSuspensionSpan = tooFastSuspensionSpan; 
     _threads = Enumerable.Repeat(new ThreadStart(DoWork), numThreads) 
          .Select(ts => new Thread(ts)) 
          .ToArray(); 
    } 

    public void Run() 
    { 
     foreach (var thread in _threads) 
     { 
      thread.Start(); 
     } 
    } 

    private void DoWork() 
    { 
     while (!IsWorkComplete()) 
     { 
      try 
      { 
       // Do work here 

      } 
      catch (TooFastException) 
      { 
       SuspendAll(); 
      } 
     } 

    } 

    private void SuspendAll() 
    { 
     lock (_locker) 
     { 
      // We don't want N near-simultaneous failures causing a sleep-duration of N * _tooFastSuspensionSpan 
      // 1 second is arbitrary. We can't be deterministic about it since we are forcefully suspending threads 
      var now = DateTime.Now; 
      if (now.Subtract(_lastSuspensionTime) < _tooFastSuspensionSpan + TimeSpan.FromSeconds(1)) 
       return; 

      _lastSuspensionTime = now; 

      var otherThreads = _threads.Where(t => t.ManagedThreadId != Thread.CurrentThread.ManagedThreadId).ToArray(); 

      foreach (var otherThread in otherThreads) 
       otherThread.Suspend(); 

      Thread.Sleep(_tooFastSuspensionSpan); 

      foreach (var otherThread in otherThreads) 
       otherThread.Resume(); 
     } 
    } 

} 
+0

我理解你的解決方案。這說得通。謝謝。 – Faruz 2010-08-24 05:50:21

0

您需要創建工作線程的庫存,那麼也許你可以使用Thread.suspend和恢復方法。請注意,使用掛起可能很危險(例如,掛起之前線程可能已獲得鎖定)。由於這些問題,暫停/恢復已被標記爲廢止。