Nickolay Kondratyev
Nickolay Kondratyev

Reputation: 5211

C# is it possible to change priority of acquiring a lock?

If there are multiple threads all waiting on the same lock is it possible to have the Main thread have higher priority in acquiring the lock. Meaning that if worker threads go to the lock statement before the main thread, the main thread would acquire the lock before the other threads that were already waiting on it.

Upvotes: 9

Views: 3968

Answers (3)

John Henckel
John Henckel

Reputation: 11347

Here is another solution. I has a lot of lines, but it is pretty simple. The function DoSomethingSingle will be called only one thread at a time, and those with the highPriority flag will get preference.

    static int numWaiting = 0;
    static object single = new object();

    ResultType DoSomething(string[] argList, bool highPriority = false)
    {
        try
        {
            if (highPriority)
            {
                Interlocked.Increment(ref numWaiting);
            }

            for (;;)
            {
                lock (single)
                {
                    if (highPriority || numWaiting == 0)
                    {
                        return DoSomethingSingle(argList);
                    }
                }
                // Sleep gives other threads a chance to enter the lock
                Thread.Sleep(0);
            }
        }
        finally
        {
            if (highPriority)
            {
                Interlocked.Decrement(ref numWaiting);
            }
        }
    }

This allows two priority levels. Guaranteed that a low priority thread will gain access to the resource only if there are no high priority threads waiting for it.

edit: change to interlock incr/dec

Upvotes: 1

Servy
Servy

Reputation: 203811

Through a native lock statement, no. Through your own custom locking mechanism, sure, if you're willing to spend the time and effort to develop it.

Here's my draft a a solution. It may or may not work, and may not be super efficient, but it's at least a starting place:

public class Lock
{
    bool locked = false;

    private object key = new object();
    SortedDictionary<int, Queue<ManualResetEvent>> notifiers =
        new SortedDictionary<int, Queue<ManualResetEvent>>();

    ManualResetEvent specialNotifier = null;

    public void Lock()
    {
        lock (key)
        {
            if (locked)
            {
                ManualResetEvent notifier = new ManualResetEvent(false);

                int priority = getPriorityForThread();

                Queue<ManualResetEvent> queue = notifiers[priority];
                if (queue == null)
                {
                    queue = new Queue<ManualResetEvent>();
                    notifiers[priority] = queue;
                }

                queue.Enqueue(notifier);

                notifier.WaitOne();
            }
            else
            {
                locked = true;
            }
        }
    }

    private static int getPriorityForThread()
    {
        return 0;
    }

    public void Release()
    {
        lock (key)
        {
            foreach (var queue in notifiers.Values)
            {
                if (queue.Any())
                {
                    var notifier = queue.Dequeue();
                    notifier.Set();
                    return;
                }
            }
            locked = false;
        }
    }
}

Upvotes: 2

Henk Holterman
Henk Holterman

Reputation: 273179

No, the lock statement maps to System.Threading.Monitor.Enter() (MSDN) and there is no overload that accepts a priority parameter.

The closest thing I can think of is a ReaderWriterLock(Slim) but I would seriously reconsider the design that leads to this request. There probably are better ways to achieve what you need.

Upvotes: 8

Related Questions