ReaderWriterLockSlim on Windows Phone 8 and the seemingly random MethodAccessException
TL;DR: Don't use the ReaderWriterLockSlim class on Windows Phone 8 RTM, it has a bug that appears only under contention.
Windows Phone 8’s move to the NT kernel has had a lot of advantages for the developer, such as the move to the same .NET CLR as the Desktop Windows, but also the ability to have multi-core based environment.
More specifically, there is one access synchronization – the ReaderWriterLockSlim – which makes a lot of sense in real multi-core environment.
I’ve been using this class to synchronize access to a dictionary abstraction for performance reasons and also for legacy reasons, since that the Concurrent Collections are available. Note that we do have a new tool in the toolbox, the BCL Immutable Collections, that are becoming my new preferred way for creating collections.
[more]
The (seemingly) random System.MissingMethodException
After moving a project to Windows Phone 8, I started seeing this MethodAccessException sporadically, seemingly without any reason :
[System.MethodAccessException]
Attempt by method 'System.Threading.ReaderWriterLockSlim.WaitOnEvent(System.Threading.EventWaitHandle, UInt32 ByRef, TimeoutTracker)' to access method 'System.Threading.WaitHandle.WaitOne(Int32, Boolean)' failed.
Which seems a bit odd.
I was able to reproduce the issue this way :
var r = new ReaderWriterLockSlim(); r.TryEnterUpgradeableReadLock(-1); r.TryEnterWriteLock(-1); ThreadPool.QueueUserWorkItem(_ => { r.TryEnterWriteLock(-1); });
With this code pasted in the constructor of the app.xaml.cs file of an empty app.
This means that until there is actual contention on the lock, the bug will not show up. This makes it show up seemingly randomly.
A bit of geeky digging
As always, I just can't let an issue like this not deeply understood, and I've dug a bit deeper to understand why this is happening.
In Windows Phone 8, the ReaderWriterLockSlim type is in the System.Core.dll assembly, and considering the exception stack trace and message, the ReaderWriterLockSlim.WaitOnEvent method is trying to access the WaitHandle.WaitOne(Int32, Boolean) method which is located in the mscorlib.dll assembly.
The problem is actually pretty simple: The WaitHandle.WaitOne(Int32, Boolean) method is declared as private in another assembly, making the runtime fail when linking the method.
This brings another interesting insight on how Microsoft handles the Framework, because this code could not have been compiled using the current set of assemblies. Somehow, the System.Core.dll was built using a different mscorlib.dll which has this method either public or most probably internal (because mscorlib.dll has the InternalsVisibleTo("System.Core") attribute set).
A workaround
To my knowledge, this issue is present in Windows Phone 8 RTM (Apollo), and I’ve not been able to validate that this is still present in the Portico update.
For the time being, I’ve moved back to a Monitor based synchronization mechanism until this gets fixed.
So in short, don’t use ReaderWriterLockSlim on Apollo.