I'm getting a The write lock is being released without being held exception when exiting write mode on a ReaderWriterLockSlim on macOS.
Debugging this issue has led me to conclude, that apparently my call toExitWriteLock happens on a different thread than where I started, albeit in a weird way.
When I debug it, Thread.CurrentThread.ManagedThreadId will indicate I'm still on thread 1 where I acquired the lock, but Environment.ManagedThreadId which is what ReaderWriterLockSlim uses, indicates I'm on thread 6.
This does not seem to happen on CoreCLR.
The code paths involved do not include any calls to Thread.Start or asynchronous Task code. It really all should be happening on the same thread (which Thread.CurrentThread.ManagedThreadId also seems to indicate is true).
The rest of the app does have asynchronous Task code though.
Unfortunately, I haven't yet been able to make a repro case. It does seem to make a difference though if GC is invoked between the calls to EnterWriteLock and ExitWriteLock.
Any ideas as how to better debug this?
This is basically what I'm doing, but I don't think this helps much.
using System;
using System.Collections.Generic;
using System.Threading;
namespace Test
{
public struct WriteLock : IDisposable
{
private readonly LockManager lockManager;
internal WriteLock(LockManager lockManager)
{
this.lockManager = lockManager;
}
public void Dispose()
{
this.lockManager.ReleaseWriteLock();
}
}
public class LockManager : IDisposable
{
private ReaderWriterLockSlim readerWriterLock;
public LockManager()
{
this.readerWriterLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
}
public IDisposable AcquireWriteLock()
{
// Enter the lock
if (!this.readerWriterLock.TryEnterWriteLock(-1))
{
throw new Exception("Could not enter write lock");
}
Console.WriteLine("Entered write lock: " + Thread.CurrentThread.ManagedThreadId);
// Return a new instance of a write lock
return new WriteLock(this);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
internal void ReleaseReadLock()
{
this.readerWriterLock.ExitReadLock();
}
internal void ReleaseWriteLock()
{
this.readerWriterLock.ExitWriteLock();
}
protected virtual void Dispose(bool disposing)
{
Console.WriteLine("Disposing lock manager... disposing: " + disposing);
if (disposing)
{
if (this.readerWriterLock != null)
{
this.readerWriterLock.Dispose();
this.readerWriterLock = null;
}
}
}
public static void Main(string[] args)
{
using (var lockMan = new LockManager())
using (var locky = lockMan.AcquireWriteLock())
{
//Lots of stuff happening in here. No Task awaits though...
}
}
}
}
I'm getting a
The write lock is being released without being heldexception when exiting write mode on aReaderWriterLockSlimon macOS.Debugging this issue has led me to conclude, that apparently my call to
ExitWriteLockhappens on a different thread than where I started, albeit in a weird way.When I debug it,
Thread.CurrentThread.ManagedThreadIdwill indicate I'm still on thread 1 where I acquired the lock, butEnvironment.ManagedThreadIdwhich is whatReaderWriterLockSlimuses, indicates I'm on thread 6.This does not seem to happen on CoreCLR.
The code paths involved do not include any calls to Thread.Start or asynchronous Task code. It really all should be happening on the same thread (which
Thread.CurrentThread.ManagedThreadIdalso seems to indicate is true).The rest of the app does have asynchronous Task code though.
Unfortunately, I haven't yet been able to make a repro case. It does seem to make a difference though if GC is invoked between the calls to EnterWriteLock and ExitWriteLock.
Any ideas as how to better debug this?
This is basically what I'm doing, but I don't think this helps much.