.NET框架是否能够以某种方式实现对共享资源的访问,以致某些尝试访问该资源的Writer优先于其他资源?
我的问题有以下限制:
1.只能向资源发出1个并发写请求
2.有许多作家等待访问这个资源,但有些作家优先于其他作家(低优先级作家的饥饿是可以的)。
3.线程亲和力是一项非要求。一个线程可以设置锁定,但另一个线程可以重置它
4.所有Writer线程都来自同一个进程。
简而言之,我需要一个暴露其等待队列的原语,并允许对其进行修改访问。如果没有任何这样的事情,有关我如何继续为自己构建一个的提示,使用已经可用的类,如Semaphore?
答案 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的建议,使用标准的监视器功能来锁定和发出什么以及何时做的信号。