线程同步:共享资源和具有不同资源数量需求的操作

时间:2011-12-19 06:04:06

标签: c# multithreading

我有以下任务:

有一个等效资源池(例如输入槽)和一组要使用此池执行的操作。

每个动作都在一个单独的线程中执行。

每个操作都需要不同数量的输入插槽。

我想使用信号量之类的东西来执行以下任务:

所有操作线程同时执行

当所需数量的输入槽可以自由使用时执行操作

操作完成后,插槽将被释放

我不能使用常规信号量,因为它不可能设置信号量负值初始值或递减值直到它变为负值

所以我需要使用WaitMultiple(int N)函数的“信号量”,这样做就像“等到资源值达到N”

有什么建议我可以解决吗? 我更喜欢线程阻塞/释放,我买不起活动循环

2 个答案:

答案 0 :(得分:3)

我不确定信号量在这里是否有用。

我认为您可以使用线程池和CS / mutex保护部分中的一些代码执行此操作。将操作放在集合中(列表/队列/堆栈,最适合您的调度算法),并初始化插槽计数。然后,只要通过完成操作释放插槽,就进入CS并决定在给定当前插槽计数的情况下执行哪些操作。将这些操作提交给线程池,适当减少插槽数并退出CS。

'吸入式计数'可能是一个简单的整数或一些复杂类的集合数 - 并不重要。

每当空闲插槽数增加时,您必须决定将哪个操​​作分派到线程池。您将需要某种算法,因为插槽释放似乎可以运行多个操作 - 您是否可以先执行具有最高插槽要求的操作?

我没有看到任何需要单独的调度程序线程,当然也没有任何CPU循环!我担心任何基于线程的解决方案都试图通过等待一些同步对象来获得可用的插槽来累积一个插槽目标,这将是一个死锁风险 - 许多线程可能会遇到部分插槽计数,因此阻止了前进。此外,您将无法调整算法,例如,阻止具有较高插槽要求的操作被饿死。

答案 1 :(得分:1)

您可以实现自己的快速信号量,并可能出现负数。例如,有一个类MySemaphore,如下所示:

public class MySemaphore
{
    private int size; // number of occupied resources
    private readonly int capacity; // total capacity

    public MySemaphore(int size, int capacity)
    {
        this.size = size;
        this.capacity = capacity;
    }

    public void Lock(int count) // acquire "count" resources
    {
        lock(this)
        {
            while(capacity - size < count)
            {
                Monitor.Wait(this);
            }
            size += count;
        }
    }        

    public void Unlock(int count) // release "count" resources
    {
        lock(this)
        {
            size -= count;
            Monitor.PulseAll(this);
        }
    }
}