The resource has its own lock and unlock code to handle concurrency. A resource can be changed by any thread.
There is a yellow flag. I believe that the design in which you protect resources (rather than protect them) is usually better in the long run.
When button1 is pressed, its handler performs some modification of r itself, and then asynchronously calls _IndependentResourceModifierAsync (), which performs some modification of r in the given task. _IndependentResourceModifierAsync () gets an r lock before this. In addition, since the handler tinkers with r, it also gets an r-lock.
And there is a red flag. Recursive castles are almost always a bad idea. I explain my arguments on my blog.
There was also another warning that I chose regarding design:
If button1 or button2 is pressed when the resource is locked by the main thread, an exception will be thrown. (It is not possible to use a monitor or Mutex because they are flow controlled)
It doesnβt sound like that. Is there any other way to do this? Disabling the buttons as the state changes seems more enjoyable.
I highly recommend refactoring to remove the requirement for lock recursion. Then you can use SemaphoreSlim
with WaitAsync
to asynchronously obtain a lock and Wait(0)
for "try-lock".
So your code will look something like this:
class Resource { private readonly SemaphoreSlim mutex = new SemaphoreSlim(1);
I was looking a lot for someone else who had this problem, but failed. This probably means that I'm making the situation too complicated, but I'm curious what people can say about it.
For a long time it was impossible (in general, a period, a complete stop). With .NET 4.5, this is possible, but not very. It is very difficult. I do not know who actually does this in production, and I certainly do not recommend it.
However, I played with asynchronous recursive locks as an example in my AsyncEx library (it will never be part of the public API). You can use it like this (following the agreement of AsyncEx already canceled tokens acting synchronously ):
class Resource { private readonly RecursiveAsyncLock mutex = new RecursiveAsyncLock(); public RecursiveLockAsync.RecursiveLockAwaitable LockAsync(bool immediate = false) { if (immediate) return mutex.LockAsync(new CancellationToken(true)); return mutex.LockAsync(); } } async void button1Click(..) { using (r.LockAsync(true)) { ...
The code for RecursiveAsyncLock
not very long, but it is terribly thought-provoking. It starts with an implicit asynchronous context , which I describe in detail on my blog (which is difficult to understand on my own), and then uses custom expectations to "enter" the code at the right time in the async
end-user methods.
You are right on the verge of someone experimenting. RecursiveAsyncLock
is not fully tested and probably never will be.
Drag the conductor carefully. There will be dragons.