2016-12-28 103 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

非常感谢解释执行的顺序。这是我的不好:(我没有注意到使用“使用”和“任务”的错误。再次感谢。 –