You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Instead of using semaphore (SempahoreSlim) as a means to use to lock asynchronous content, which may result in deadlock if it is re-acquired without prior releasing on the same Task execution context.
It would be a good idea if we have a low cost, yet that prevents deadlocking upon re-entrant.
Inspired by #28194, I tested out the possibility by combining the usage of AsyncLocal and SempahoreSlim, [Here in this Repo].
Upon writing tests, it is suggested that this is possibly do-able.
Here's more of the detail of how I approached this idea:
AsyncLock utilizes two main classes SemphoreSlim and AsyncLocal; the actual lock is maintained by SemphoreSlim and the re-entrant check is done by using AsyncLocal.
When locking with AsyncLock, it returns an object implementing ILockHandle, which can either contain actual content that does the unlocking when Dispose() is called, or does absolutely nothing. The former one is acquired when the current Task has not acquired AsyncLock, the latter one is returned when AsyncLock detects when it already acquired the lock.
The detection of the current lock acquired by the current task is achieved through AsyncLocal, the underlying value of AsyncLocal is (almost) different when it's in different Task. When it's underlying value is null we know that the current Task hasn't acquired the lock and is put into the semaphore; if it's not null then we know the current Task has already acquired a lock given by this current AsyncLock instance, and would not await the semaphore and returns an empty ILockHandle.
Thoughts and Questions
Few problems araised when there's a limitation of what AsyncLocal can do.
If the lock acquiring process is inside the scope of ExecutionContext.SuppressFlow(), this would effectively break the re-entrant check.
A good solution I came up with would be further integrating with Task, making it maintain a record of acquired AsyncLock without being affected by SuppressFlow (or just make SuppressFlow ignore the tracking of acquired locks)
The text was updated successfully, but these errors were encountered:
I think that reentrant locks are problematic, for reasons explained in this blog post by Stephen Cleary. And while .Net already has reentrant locks (including lock), I don't think more should be added.
We don't currently have any plans to add such a type to the core libraries. If you come up with a solution that works well for you, please consider releasing it as a nuget package for others who may be interested as well. However, as @svick highlights, this isn't a pattern we intend to promote.
Inspired by #28194 and it's related resources.
Usage
Instead of using semaphore (SempahoreSlim) as a means to use to lock asynchronous content, which may result in deadlock if it is re-acquired without prior releasing on the same Task execution context.
It would be a good idea if we have a low cost, yet that prevents deadlocking upon re-entrant.
Inspired by #28194, I tested out the possibility by combining the usage of
AsyncLocal
andSempahoreSlim
, [Here in this Repo].Upon writing tests, it is suggested that this is possibly do-able.
Here's more of the detail of how I approached this idea:
Thoughts and Questions
Few problems araised when there's a limitation of what AsyncLocal can do.
If the lock acquiring process is inside the scope of
ExecutionContext.SuppressFlow()
, this would effectively break the re-entrant check.A good solution I came up with would be further integrating with
Task
, making it maintain a record of acquiredAsyncLock
without being affected bySuppressFlow
(or just make SuppressFlow ignore the tracking of acquired locks)The text was updated successfully, but these errors were encountered: