Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Deadlock in ReactiveCommand if InvokeCommand and CanExecute are triggered from different threads #3029

Open
erikm-g opened this issue Nov 23, 2021 · 0 comments
Labels

Comments

@erikm-g
Copy link

erikm-g commented Nov 23, 2021

If a reactive command is executed from a pipeline using the InvokeCommand helper method on a background thread and the canExecute observable ticks at the same time on another thread a deadlock occurs.

The thread executing the command will acquire a look in the Switch in WithLatestFromFixed in ReactiveCommandsMixins and will then update isExecuting that will try to acquire the lock in CombineLatest between canExecute and isExecuting defined in the ReactiveCommand constructor.

The thread advancing CanExecute will acquire the lock in CombineLatest between canExecute and isExecuting defined in the ReactiveCommand constructor which is then propagated to the Select in WithLatestFromFixed in ReactiveCommandMixins that tries to acquire the lock in the Switch to update the source observable.

I am kind of new to ReactiveUI so not sure of how threading and scheduling is supposed to be handled, but as far as I can understand from the documentation one of the features is that invoking and executing commands can be done on any thread while the view model can still observe it on the UI thread. If this is a misunderstanding, I think this should be explained in the documentation.

Steps To Reproduce
I tried to simplify the steps to reproduce as far as possible and came up with this unit test. It will get stuck in a deadlock and never finish.

        [Test]
        public async Task DeadlockExample()
        {
            var canExecute = new Subject<bool>();
            var command = ReactiveCommand.Create(() => {}, canExecute);
            Observable.Interval(TimeSpan.FromMilliseconds(10), RxApp.TaskpoolScheduler).Select(_ => Unit.Default).InvokeCommand(command);

            for (int i = 0; i < 1000; i++)
            {
                canExecute.OnNext(true);
                await Task.Delay(3);
                canExecute.OnNext(false);
            }
        }

Expected behaviour
No deadlock, i.e. the test above passes.
OR
That the command section of the handbook (https://www.reactiveui.net/docs/handbook/commands/) describes the restrictions on multi threaded calls to reactive command.

Environment

  • OS: Windows 10 Enterprise
  • Version 20H2
  • Device: PC
  • ReactiveUI Version: 16.2.6
@erikm-g erikm-g added the bug label Nov 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant