Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 按优先级排序的写入程序对共享资源的访问?_C#_.net_Multithreading - Fatal编程技术网

C# 按优先级排序的写入程序对共享资源的访问?

C# 按优先级排序的写入程序对共享资源的访问?,c#,.net,multithreading,C#,.net,Multithreading,NET framework是否提供了一种实现对共享资源的访问的能力,以使一些试图访问该资源的编写器优先于其他编写器 我的问题有以下限制: 1.只能向资源授予1个并发写入请求 2.有许多写入程序正在等待访问此资源,但有些写入程序的优先级高于其他写入程序(缺少低优先级写入程序是可以的)。 3.线程关联不是必需的。一个线程可以设置锁,但另一个线程可以重置锁。 4.所有写入线程都来自同一进程 简言之,我需要一个原语来公开它的等待队列并允许修改访问它。如果没有这样的东西,那么有没有关于如何使用已经可用的类

NET framework是否提供了一种实现对共享资源的访问的能力,以使一些试图访问该资源的编写器优先于其他编写器

我的问题有以下限制:
1.只能向资源授予1个并发写入请求
2.有许多写入程序正在等待访问此资源,但有些写入程序的优先级高于其他写入程序(缺少低优先级写入程序是可以的)。
3.线程关联不是必需的。一个线程可以设置锁,但另一个线程可以重置锁。
4.所有写入线程都来自同一进程


简言之,我需要一个原语来公开它的等待队列并允许修改访问它。如果没有这样的东西,那么有没有关于如何使用已经可用的类(如Semaphore)为自己构建一个的提示?

使用优先级队列来保存挂起的请求列表。请参见此处:。
按照kenny的建议,使用Stanard Monitor功能来锁定和通知要做什么和什么时候做。

下面是一些我可以想出的快速脏代码。我会改进这一点,但作为一个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;
    }
}
公共类优先级锁定
{
private List waitQueue;//共享资源的等待队列
私有信号量waitQueueSemaphore;//确保安全访问等待队列本身
公共优先级锁()
{
waitQueue=新列表();
waitQueueSemaphore=新信号量(1,1);
}
公共bool WaitOne(内部位置=0)
{
//CountdownEvent的初始计数必须为1
//否则,它将在信号状态下创建
位置++;
bool containsGrantedRequest=false;//用于检查等待队列是否仍包含拥有锁的对象的标志
倒计时事件(此请求=位置)
cdEvent.AddCount();
else if(cdEvent.CurrentCount==位置)
thisRequest.AddCount();
如果(cdEvent.CurrentCount==0)
ContainesGrantedRequest=true;
}
waitQueue.Add(此请求);
foreach(waitQueue中的CountdownEvent cdEvent)
if(cdEvent.CurrentCount<最小位置幅值)
leastPositionMagnitude=cdEvent.CurrentCount;
//如果没有人持有锁,则将锁授予当前请求
if(containsGrantedRequest==false&&thisRequest.CurrentCount==leastPositionMagnitude)
此请求。信号(最小位置幅值);
waitQueueSemaphore.Release();
//现在实际等待这个请求;如果已经发出信号,它将立即结束
thisRequest.Wait();
返回true;
}
公共int Release()
{
int waitingCount=0,i=0,positionLeastMagnitude=Int32.MaxValue;
int grantedIndex=-1;
waitQueueSemaphore.WaitOne();
foreach(waitQueue中的CountdownEvent cdEvent)
{

如果(cdEvent.CurrentCount什么资源?某种类型的流?让写入程序尝试锁定,如果我不能将自己放入一个优先级队列中如何。当带锁的写入程序即将释放锁时,它可以检查队列并抓取下一个写入程序。@Will-该资源是一个COM dll,它不允许对任何方法或pro进行并发访问perty被它暴露了。它抛出一个“对象还没有准备好”异常,以防并发访问发生。@kenny-让我想想,如果我能利用你的想法,我明天会回复(这里已经很晚了)。你看过ReaderWriterLockSlim吗?那可以,我会试试。在.NET framework 4中,似乎还有一个名为System.Threading.CountdownEvent的新类,我可以用它创建我自己的机制。我将运行一些性能测试,看看是哪个实现(优先级队列+互斥体/监视器,还是我的类)资源密集度较低。我也希望您能就如何优化这一点发表意见。