-
-
Notifications
You must be signed in to change notification settings - Fork 191
Description
Describe the bug 🐞
Create two observables that call ToObservableChangeSet with expireAfter and they may end up in deadlock.
The TaskPoolScheduler thread that handles the item expiration can end up with both scheduled expirations nested on the stack holding locks that deadlock the adding threads.
Step to reproduce
Create a console project and add this code to Program.cs
using DynamicData;
using System.Reactive.Linq;
namespace DynamicDataDeadlock;
internal class Program
{
static void Main(string[] args)
{
Observable.Interval(TimeSpan.FromMilliseconds(250))
.Select(x => new Item(x % 100))
.ToObservableChangeSet(x => x.Value, expireAfter: _ => TimeSpan.FromSeconds(1))
.Subscribe(x => Console.WriteLine($"{string.Join(',', x)}"));
Observable.Interval(TimeSpan.FromMilliseconds(250))
.Select(x => new Item2(x % 71))
.ToObservableChangeSet(x => x.Value, expireAfter: _ => TimeSpan.FromSeconds(1))
.Subscribe(x => Console.WriteLine($"{string.Join(',', x)}"));
Console.ReadKey();
}
}
internal class Item
{
public Item(long x) => Value = x;
public long Value { get; }
}
internal class Item2
{
public Item2(long x) => Value = x;
public long Value { get; }
}
Run the program in the debugger and it will eventually stop outputting lines. Pause the program and inspect the parallel threads to observe the deadlock.
Removing the console debug will reach deadlock faster.
Reproduction repository
https://github.com/aguahombre/DynamicDataDeadlock
Expected behavior
The two subscriptions run independently and never deadlock.
Screenshots 🖼️
Here is the parallel threads window showing threads 27772 and 12496 in deadlock.
IDE
Visual Studio 2022
Operating system
Windows 10, Linux Bookworm
Version
17.13.6
Device
PC, RPI4B
DynamicData Version
9.2.1
Additional information ℹ️
No response
