动态降低信号量的容量

时间:2013-12-06 00:59:53

标签: c# concurrency thread-safety locking semaphore

我一直在尝试使用Semaphore来控制我的服务可以处理的请求数。即。

class Service : IDisposable {
    SemaphoreSlim s = new SemaphoreSlim(InitialCapacity);

    ....
    async void ProcessRequest() {
        await s.WaitAsync();
        try {
             ......
        } finally {
            s.Release();
        }
    }
}

我遇到的问题有2个我不知道如何解决。我一直在使用类似的黑客来解决这些问题,但我想知道是否有更好的方法

  1. 我希望能够动态更改服务类的容量,所以我有类似的东西。

    void ChangeCapacity(int newCapacity) {
        int extraRequestsCount = newCapacity - oldCapacity;
        if (extraRequestsCount > 0) {
            s.Release(extraRequestsCount);
        }
        else if (extraRequestsCount < 0) {
            for (int i = 0; i < -extraRequestsCount; i++) {
                s.WaitAsync(); // try to steal some resources, over time...
            }
        }
    }
    
  2. 在dispose方法中,我想确保在处理信号量之前完成所有请求处理,否则我的ProcessRequest()中的s.Release()调用会抛出ObjectDisposedException,所以我做了以下

    public void Dispose() {
        if (s!= null) {
            for (int i = 0; i < oldCapacity; i++) {
                s.Wait();
            }
            s.Dispose();
        }
    }
    
  3. 请注意,我一直在使用循环手动等待多次。如果容量很大,这真的很慢。有一个更好的方法吗?信号量有一个Release(int count),为什么没有Wait(int count)?

1 个答案:

答案 0 :(得分:1)

我可能做的是在进行调整时,用一个具有所需容量的新信号量替换你的信号量实例,并将所有未来的工作分配给该信号量。在完成所有线程的引用之前,现有的和现在解除引用的信号量不会被垃圾收集,所以只要你将信号量变量本地分配给每个线程就应该是安全的。