Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

PriorityLock - Release locks by priority

, 30 Nov 2006
A Monitor like class that releases locks by priority.
prioritylock.zip
prioritylock_src.zip
PriorityLock
Properties
PriorityLockTest
bin
Release
Properties
using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using BenTools.Data;

namespace Senthil.Concurrency.Utilities
{
    public class PriorityLock
    {
        const int InvalidThreadId = -1;
        Dictionary<int, int> threadLockCountDictionary = new Dictionary<int, int>();

        class Item : IComparable
        {
            private int priority;

            public int Priority
            {
                get { return priority; }
                set { priority = value; }
            }
            private object tag;
            public Item(int priority, object tag)
            {
                this.priority = priority;
                this.tag = tag;
            }

            public object Tag
            {
                get { return tag; }
            }

            public int CompareTo(object other)
            {
                return ((Item)other).priority - this.priority;
            }
        }

        IPriorityQueue priorityQueue = new BinaryPriorityQueue();
        object queueLock = new object();

        bool isLockFree = true;
        bool isThreadScheduled = false;
        int threadHoldingLock = InvalidThreadId;

        public PriorityLock()
        {
        }

        public void Lock(int priority)
        {
            object waitObject = null;

            bool waitForLock = true;
            lock (queueLock)
            {
                if ((isThreadScheduled == false && IsLockFree()) || CurrentThreadHoldsLock())
                {
                    SetCurrentThreadAsLockOwner();
                    waitForLock = false;
                }
                else
                {
                    waitObject = new object();
                    Item item = new Item(priority, waitObject);
                    priorityQueue.Push(item);
                }
            }
            if (waitForLock)
            {
                lock (waitObject)
                {
                    Monitor.Wait(waitObject);
                    lock (queueLock)
                    {
                        isThreadScheduled = false;
                        SetCurrentThreadAsLockOwner();
                    }
                }
            }
        }

        public void Unlock()
        {
            Item nextItem = null;
            lock (queueLock)
            {
                if (!IsLockHeldByCallingThread())
                {
                    throw new InvalidOperationException("Cannot call Unlock as current thread has not called Lock.");
                }

                SetLockFree();
                
                if (IsLockFree() && priorityQueue.Count != 0)
                {
                    nextItem = (Item)priorityQueue.Pop();
                    isThreadScheduled = true;
                }
            }
            
            if (nextItem != null)
            {
                object waitObject = nextItem.Tag;
                lock (waitObject)
                {
                    Monitor.Pulse(waitObject);
                }
            }
        }

        private bool IsLockHeldByCallingThread()
        {
            return Thread.CurrentThread.ManagedThreadId == threadHoldingLock;
        }

        private bool IsLockFree()
        {
            return isLockFree;
        }

        private bool CurrentThreadHoldsLock()
        {
            return (threadHoldingLock == Thread.CurrentThread.ManagedThreadId);
        }

        private void SetCurrentThreadAsLockOwner()
        {
            threadHoldingLock = Thread.CurrentThread.ManagedThreadId;

            IncrementThreadLockCount();
            isLockFree = false;
        }

        private void SetLockFree()
        {
            int decrementedLockCount = DecrementLockCount();
            if (decrementedLockCount == 0)
            {
                threadHoldingLock = InvalidThreadId;
                isLockFree = true;
            }
        }

        private int IncrementThreadLockCount()
        {
            int currentThreadId = Thread.CurrentThread.ManagedThreadId;
            int lockCount = 0;
            threadLockCountDictionary.TryGetValue(currentThreadId, out lockCount);
            
            ++lockCount;
            threadLockCountDictionary[currentThreadId] = lockCount;
            return lockCount;
        }

        private int DecrementLockCount()
        {
            int currentThreadId = Thread.CurrentThread.ManagedThreadId;
            int lockCount = 0;
            threadLockCountDictionary.TryGetValue(currentThreadId, out lockCount);
            
            lockCount--;

            if (lockCount == 0)
            {
                threadLockCountDictionary.Remove(currentThreadId);
            }
            else if (lockCount > 0)
            {
                threadLockCountDictionary[currentThreadId] = lockCount;
            }
            else
            {
                throw new InvalidOperationException("Cannot call Unlock without corresponding call to Lock");
            }

            return lockCount;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

S. Senthil Kumar
Software Developer Atmel R&D India Pvt. Ltd.
India India
I'm a 27 yrs old developer working with Atmel R&D India Pvt. Ltd., Chennai. I'm currently working in C# and C++, but I've done some Java programming as well. I was a Microsoft MVP in Visual C# from 2007 to 2009.
 
You can read My Blog here. I've also done some open source software - please visit my website to know more.

| Advertise | Privacy | Mobile
Web01 | 2.8.140821.2 | Last Updated 30 Nov 2006
Article Copyright 2006 by S. Senthil Kumar
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid