优先级写入者访问共享资源?

时间:2011-01-15 15:40:10

标签: c# .net multithreading

.NET框架是否能够以某种方式实现对共享资源的访问,以致某些尝试访问该资源的Writer优先于其他资源?

我的问题有以下限制:
1.只能向资源发出1个并发写请求 2.有许多作家等待访问这个资源,但有些作家优先于其他作家(低优先级作家的饥饿是可以的)。
3.线程亲和力是一项非要求。一个线程可以设置锁定,但另一个线程可以重置它 4.所有Writer线程都来自同一个进程。

简而言之,我需要一个暴露其等待队列的原语,并允许对其进行修改访问。如果没有任何这样的事情,有关我如何继续为自己构建一个的提示,使用已经可用的类,如Semaphore?

2 个答案:

答案 0 :(得分:1)

这是我能想到的一些快速代码。我会对此进行改进,但作为POC,这是有效的......

public class PrioritisedLock
{
    private List<CountdownEvent> waitQueue; //wait queue for the shared resource
    private Semaphore waitQueueSemaphore; //ensure safe access to wait queue itself

    public PrioritisedLock()
    {
        waitQueue = new List<CountdownEvent>();
        waitQueueSemaphore = new Semaphore(1, 1);
    }

    public bool WaitOne(int position = 0)
    {
        //CountdownEvent needs to have a initial count of 1
        //otherwise it is created in signaled state
        position++;
        bool containsGrantedRequest = false; //flag to check if wait queue still contains object which owns the lock

        CountdownEvent thisRequest = position<1 ? new CountdownEvent(1) : new CountdownEvent(position);
        int leastPositionMagnitude=Int32.MaxValue;
        waitQueueSemaphore.WaitOne();

        //insert the request at the appropriate position
        foreach (CountdownEvent cdEvent in waitQueue)
        {
            if (cdEvent.CurrentCount > position)
                cdEvent.AddCount();
            else if (cdEvent.CurrentCount == position)
                thisRequest.AddCount();

            if (cdEvent.CurrentCount == 0)
                containsGrantedRequest = true;
        }

        waitQueue.Add(thisRequest);

        foreach (CountdownEvent cdEvent in waitQueue)
            if (cdEvent.CurrentCount < leastPositionMagnitude)
                leastPositionMagnitude = cdEvent.CurrentCount;

        //If nobody holds the lock, grant the lock to the current request
        if (containsGrantedRequest==false && thisRequest.CurrentCount == leastPositionMagnitude)
            thisRequest.Signal(leastPositionMagnitude);

        waitQueueSemaphore.Release();

        //now do the actual wait for this request; if it is already signaled, it ends immediately
        thisRequest.Wait();

        return true;
    }

    public int Release()
    {
        int waitingCount = 0, i = 0, positionLeastMagnitude=Int32.MaxValue;
        int grantedIndex = -1;

        waitQueueSemaphore.WaitOne();

        foreach(CountdownEvent cdEvent in waitQueue)
        {
            if (cdEvent.CurrentCount <= 0)
            {
                grantedIndex = i;
                break;
            }
            i++;
        }

        //remove the request which is already fulfilled
        if (grantedIndex != -1)
            waitQueue.RemoveAt(grantedIndex);

        //find the wait count of the first element in the queue
        foreach (CountdownEvent cdEvent in waitQueue)
            if (cdEvent.CurrentCount < positionLeastMagnitude)
                positionLeastMagnitude = cdEvent.CurrentCount;

        //decrement the wait counter for each waiting object, such that the first object in the queue is now signaled
        foreach (CountdownEvent cdEvent in waitQueue)
        {
            waitingCount++;
            cdEvent.Signal(positionLeastMagnitude);
        }

        waitQueueSemaphore.Release();
        return waitingCount;
    }
}

}

答案 1 :(得分:0)

使用优先级队列来保留待处理请求的列表。见这里:Priority queue in .Net。 根据kenny的建议,使用标准的监视器功能来锁定和发出什么以及何时做的信号。