2016-12-28 180 views
6

這讓我很難理解這種情況下的實際行爲。當SemaphoreSlim被處置時,實際上發生的是不執行任務。它拋出我下面exception- System.ObjectDisposedException {"The semaphore has been disposed."}代碼有什麼問題

我有一個類庫一樣 -

public class ParallelProcessor 
{ 
    private Action[] actions; 
    private int maxConcurrency; 

    public ParallelProcessor(Action[] actionList, int maxConcurrency) 
    { 
     this.actions = actionList; 
     this.maxConcurrency = maxConcurrency; 
    } 

    public void RunAllActions() 
    { 
     if (Utility.IsNullOrEmpty<Action>(actions)) 
      throw new Exception("No Action Found!"); 

     using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) 
     { 
      foreach (Action action in actions) 
      { 
       Task.Factory.StartNew(() => 
       { 
        concurrencySemaphore.Wait(); 
        try 
        { 
         action(); 
        } 
        finally 
        { 
         concurrencySemaphore.Release(); 
        } 
       }); 
      } 
     } 
    } 
} 

而且喜歡 -

class Program 
{ 
    static void Main(string[] args) 
    { 
     int maxConcurrency = 3; 
     Action[] actions = new Action[] {() => Console.WriteLine(1),() => Console.WriteLine(2),() => Console.WriteLine(3) }; //Array.Empty<Action>(); 

     ParallelProcessor processor = new ParallelProcessor(actions, maxConcurrency); 

     processor.RunAllActions(); 

     Console.ReadLine(); 
    } 
} 

使用它有誰請洗完澡一些關於它的光?提前致謝。

回答

3

您的信號被放置在using塊的末尾,但由其中創建的仍在運行的任務使用。
我建議移動信號達一流水平:

public class ParallelProcessor 
{ 
    private Action[] actions; 
    private SemaphoreSlim concurrencySemaphore; 

    public ParallelProcessor(Action[] actionList, int maxConcurrency) 
    { 
     this.actions = actionList; 
     concurrencySemaphore = new SemaphoreSlim(maxConcurrency); 
    } 

    public void RunAllActions() 
    { 
     if (Utility.IsNullOrEmpty<Action>(actions)) 
      throw new Exception("No Action Found!"); 

     foreach (Action action in actions) 
     { 
      Task.Factory.StartNew(() => 
       { 
        concurrencySemaphore.Wait(); 
        try 
        { 
         action(); 
        } 
        finally 
        { 
         concurrencySemaphore.Release(); 
        } 
       }); 
     } 
    } 
} 

或另一種方法,其中RunAllActions將阻塞,直到全部弄完:

public class ParallelProcessor 
{ 
    private Action[] actions; 
    private int maxConcurrency; 

    public ParallelProcessor(Action[] actionList, int maxConcurrency) 
    { 
     this.actions = actionList; 
     this.maxConcurrency = maxConcurrency; 
    } 

    public void RunAllActions() 
    { 
     if (Utility.IsNullOrEmpty<Action>(actions)) 
      throw new Exception("No Action Found!"); 

     using (var concurrencySemaphore = new SemaphoreSlim(maxConcurrency)) 
     { 
      Task.WaitAll(actions.Select(a => Task.Run(() => 
       { 
        concurrencySemaphore.Wait(); 
        try { a(); } 
        finally { concurrencySemaphore.Release(); } 
       })).ToArray()); 
     } 
    } 
} 
11

的問題是你的using聲明。這是事情是如何發生的:

  • 創建旗語
  • 在後臺
  • 處置信號燈的運行
  • 開始任務
  • 任務嘗試使用旗語......但是不能,因爲它的配置

選項:

  • 剛剛[R EMOVE的using聲明(這樣你就不會處理信號量的,但是這是不可能,除非你使用的是一個問題,這真的重)
  • 更改方法塊(using語句中),直到所有的任務已完成,例如通過使用Parallel.ForEach而不是調用Task.Factory.StartNew直接
  • 更改您的代碼已經完成了任務,不僅會在所有的其它任務執行處置旗語
+0

非常感謝解釋執行的順序。這是我的不好:(我沒有注意到使用「使用」和「任務」的錯誤。再次感謝。 –