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
The documentation states that ConnectionMultiplexer is fully thread-safe, but its Subscription internal class is not, causing problems in some operations such as Subscribe, SubscribeAsync, Unsubscribe, UnsubscribeAsync when called with a handler.
The issue stems from the Add(...) and Remove(...) functions, while delegates are immutable and cannot be corrupted, the += and -= operations are not atomic and not thread-safe. When a delegate updates itself, it creates a copy of its callback list, modifies it and then update its internal reference, if called from multiple threads some callbacks may be incorrectly lost or kept.
Example
I've made a very simple example that only calls Subscribe & Unsubscribe in a multi-threaded way and uses reflection to inspect Subscription._handlers to show that it incorrectly lose or keep callbacks that it should not.
(Please note that I've also tested both Async version of the same functions and had similar results)
Version: 2.8.0 (Latest Stable)
Problem
The documentation states that ConnectionMultiplexer is fully thread-safe, but its
Subscription
internal class is not, causing problems in some operations such asSubscribe
,SubscribeAsync
,Unsubscribe
,UnsubscribeAsync
when called with ahandler
.The issue stems from the
Add(...)
andRemove(...)
functions, while delegates are immutable and cannot be corrupted, the+=
and-=
operations are not atomic and not thread-safe. When a delegate updates itself, it creates a copy of its callback list, modifies it and then update its internal reference, if called from multiple threads some callbacks may be incorrectly lost or kept.Example
I've made a very simple example that only calls
Subscribe
&Unsubscribe
in a multi-threaded way and uses reflection to inspectSubscription._handlers
to show that it incorrectly lose or keep callbacks that it should not.(Please note that I've also tested both Async version of the same functions and had similar results)
Here's the output of a typical run:
Here's the output of the same program after changing
Parallel.ForEach
for a regularforeach
making it single threaded:Fix ?
A simple solution could be to add a lock around those operations. Jon Skeet has a very good article about delegate & thread-safety
I've created a PR #2769 that does exactly this and has unit tests.
Related
The following github issues are most likely related: #2115 #2458
The text was updated successfully, but these errors were encountered: