3

I have some code using a ReaderWriterLockSlim. I acquire a write lock on it when a certain object is constructed, and release it when that object is disposed some time later. However, because of where those calls are coming from, I can't guarantee that they'll be on the same thread, which is a requirement of the ReaderWriterLockSlim.

I believe a reasonable solution would be to run the construction and disposal of the object on a dedicated thread, and have the calling code wait for that task to complete (but keep the thread alive). It seems messy, but I can't think of another approach without massively restructuring our code.

Is there an existing TaskScheduler subclass that will allow me to run two tasks on the same thread?

I am of course open to another paradigm of doing this.

Smashery
  • 57,848
  • 30
  • 97
  • 128
  • 2
    are you using WPF or Windows.Forms? Or ASP.Net? That will greatly influence the answer :) – gnud Dec 05 '16 at 23:10
  • Interesting - well, the underlying library that contains the ReaderWriterLockSlim is used from several apps; some in Windows Forms and some in WPF; though the problematic case is when using it in our WPF app. – Smashery Dec 05 '16 at 23:39
  • Normal Tasks created in WPF should all be run on the same thread, the Dispatcher thread. But that is not the case for 'long-running' tasks, as well as tasks created explicitly on the thread pool. https://msdn.microsoft.com/magazine/gg598924.aspx – gnud Dec 05 '16 at 23:46
  • [Here](https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-7-asyncreaderwriterlock/) is a blog post going through how to construct a reader/writer lock designed for `async` code. – Servy Dec 07 '16 at 15:48

1 Answers1

0

I had a similar problem, so I hope that my solution is going to help you too.

Basically, the problem is that ReaderWriterLockSlim has thread affinity, meaning that thread that acquired a lock is the only one that can release it.

Solution to this is to create one more dedicated thread, but opposed to what you suggested, this thread is going to be dedicated to acquiring and releasing a lock.

I guess that your code looks something like this:

public class ClassUsingReaderWriterLockSlim
{
    private ReaderWriterLockSlim rwsLock;

    public void MethodThatAcquiresLock()
    {
        rwsLock.EnterWriteLock();
    }

    public void MethodThatReleasesLock()
    {
        rwsLock.ExitWriteLock();
    }
}

And a code that solves your problem will look like this:

public class ClassUsingReaderWriterLockSlim
{
    private ReaderWriterLockSlim rwsLock;
    Thread dedicatedThreadForReaderWriterLockSlim;
    Queue<string> commandsForDedicatedThread;

    public ClassUsingReaderWriterLockSlim()
    {
        commandsForDedicatedThread = new Queue<string>();
        dedicatedThreadForReaderWriterLockSlim = new Thread(ThreadFunction);
        dedicatedThreadForReaderWriterLockSlim.Start();
    }

    private void ThreadFunction(object obj)
    {
        while (!terminatingCondition)
        {
            // Wait until something is in queue...

            if (commandsForDedicatedThread.Count > 0)
            {
                switch (commandsForDedicatedThread.Dequeue())
                {
                    case "ENTER LOCK":
                        rwsLock.EnterWriteLock();
                    case "EXIT LOCK":
                        rwsLock.EnterWriteLock();
                    default:
                    // Do nothing...
                }
            }
        }
    }

    public void MethodThatAcquiresLock()
    {
        commandsForDedicatedThread.Enqueue("ENTER LOCK");
    }

    public void MethodThatReleasesLock()
    {
        commandsForDedicatedThread.Enqueue("EXIT LOCK");
    }
}

Well, for you production code you would make this a little differently but the basic idea is to have dedicated thread that is going to do locking and unlocking, and in this way it won't be important from which thread call comes to the methods that are supposed to lock and unlock code/resources...

Hope this helps you.