C# 集合以容纳最大数量的正在运行的任务

C# 集合以容纳最大数量的正在运行的任务,c#,multithreading,C#,Multithreading,我需要一个集合/包(某物),可以容纳最多数量的运行Task对象。向集合中添加新的正在运行的任务应该会阻止调用线程(有许多线程正在尝试添加任务,因此它应该是线程安全的),直到达到最大运行任务数时,有一个可供添加新任务的可用插槽为止。这就是我到目前为止所做的,它工作得很好 public class ConcurrentTaskLimiter { public int MaxWorkingTasks { get; } private readonly Task[] _tasks;

我需要一个集合/包(某物),可以容纳最多数量的运行
Task
对象。向集合中添加新的正在运行的
任务
应该会阻止调用线程(有许多线程正在尝试添加任务,因此它应该是线程安全的),直到达到最大运行任务数时,有一个可供添加新任务的可用插槽为止。这就是我到目前为止所做的,它工作得很好

public class ConcurrentTaskLimiter
{
    public int MaxWorkingTasks { get; }
    private readonly Task[] _tasks;
    private readonly bool[] _finished;

    public ConcurrentTaskLimiter(int maxWorkingTasks)
    {
        MaxWorkingTasks = maxWorkingTasks;
        if ((1 <= maxWorkingTasks) == false)
            throw new ArgumentOutOfRangeException(nameof(maxWorkingTasks), maxWorkingTasks, "Must be >= 1");
        _tasks = new Task[maxWorkingTasks];
        _finished = new bool[maxWorkingTasks];

        for (int i = 0; i < MaxWorkingTasks; i++)
        {
            _tasks[i] = Task.FromResult(0); // use this as finished tasks
            _finished[i] = true;
        }
    }

    public void BlockAdd(Task t)
    {
        if (t == null)
            throw new ArgumentNullException(nameof(t));

        if (t.Status == TaskStatus.Canceled
            || t.Status == TaskStatus.Faulted
            || t.Status == TaskStatus.RanToCompletion)
            return;

        lock (this)
        {
            int i;
            while (true)
            {
                for (i = 0; i < MaxWorkingTasks; i++)
                {
                    if (_finished[i])
                    {
                        _tasks[i] = t;
                        _finished[i] = false;
                        return;
                    }
                }
                i = Task.WaitAny(_tasks);
                _finished[i] = true;
            }
        }
    }
}
公共类ConcurrentTaskLimitor
{
public int MaxWorkingTasks{get;}
专用只读任务[]\u任务;
私有只读bool[]\u已完成;
公共ConcurrentTaskLimitor(int maxWorkingTasks)
{
MaxWorkingTasks=MaxWorkingTasks;

如果((1使用
SynchronizedCollection
它将为您提供开箱即用的线程安全。或者使用
System.collections.Concurrent
中的多个集合中的一个。我将使用
System.collections.Concurrent
中的一个,因为它们更新且效率更高。

使用
SynchronizedCollection
它将为您提供开箱即用的线程安全。或者使用
System.collections.Concurrent
中的一个集合。我将使用
System.collections.Concurrent中的一个集合,因为它们更新且效率更高。

.NET有一个名为的类,可以大大简化您的任务

阻止收集的实例可以使用其可容纳的任务数上限进行初始化。执行此操作时,当添加任务会导致收集超出容量时,
Add
的调用将被阻止。

.NET有一个名为的类,可以大大简化任务


阻塞收集的实例可以使用它可以容纳的任务数的上限进行初始化。当您这样做时,调用
Add
将在添加任务时阻塞,这将导致收集超出容量。

我将提出更优雅的解决方案

    public class TasksPool
    {
        public int MaxSize { get; private set; }

        public TasksPool(int maxSize)
        {
            if (maxSize < 1) throw new IndexOutOfRangeException("Should be 1 or more");
            MaxSize = maxSize;
            _semaphore = new SemaphoreSlim(maxSize-1);
        }

        private readonly SemaphoreSlim _semaphore;

        public void Add(Task t, CancellationToken token)
        {
            _semaphore.Wait(token);

            if (token.IsCancellationRequested) return;
            t.ContinueWith(q => _semaphore.Release(), token);
        }
    }
公共类TasksPool
{
public int MaxSize{get;private set;}
公共任务假脱机(int-maxSize)
{
如果(maxSize<1)抛出新的IndexOutOfRangeException(“应为1或更多”);
MaxSize=MaxSize;
_信号量=新信号量lim(maxSize-1);
}
私有只读信号量limu信号量;
公共无效添加(任务t、取消令牌)
{
_信号量。等待(令牌);
if(token.iscancellationrequest)返回;
t、 ContinueWith(q=>_semaphore.Release(),token);
}
}

我会提出更优雅的解决方案

    public class TasksPool
    {
        public int MaxSize { get; private set; }

        public TasksPool(int maxSize)
        {
            if (maxSize < 1) throw new IndexOutOfRangeException("Should be 1 or more");
            MaxSize = maxSize;
            _semaphore = new SemaphoreSlim(maxSize-1);
        }

        private readonly SemaphoreSlim _semaphore;

        public void Add(Task t, CancellationToken token)
        {
            _semaphore.Wait(token);

            if (token.IsCancellationRequested) return;
            t.ContinueWith(q => _semaphore.Release(), token);
        }
    }
公共类TasksPool
{
public int MaxSize{get;private set;}
公共任务假脱机(int-maxSize)
{
如果(maxSize<1)抛出新的IndexOutOfRangeException(“应为1或更多”);
MaxSize=MaxSize;
_信号量=新信号量lim(maxSize-1);
}
私有只读信号量limu信号量;
公共无效添加(任务t、取消令牌)
{
_信号量。等待(令牌);
if(token.iscancellationrequest)返回;
t、 ContinueWith(q=>_semaphore.Release(),token);
}
}

如果您的代码运行良好,请在codereview上发布此消息,以其他方式告知问题所在。您应该查看,它可能具有您所需的功能。如果您的代码运行良好,请在codereview上发布此消息,以其他方式告知问题所在。您应该查看,它可能具有您所需的功能。我曾想过阻止收集,但在这种情况下,如何删除/删除已完成的任务是否为新运行的任务腾出空间?我曾想过阻止收集,但在这种情况下,如何删除/删除已完成的任务以为新运行的任务腾出空间?