Cysharp / R3

The new future of dotnet/reactive and UniRx.
MIT License
1.71k stars 70 forks source link

Platform-dependent tests and ReactiveProperty race condition fix #230

Open nepolak opened 1 week ago

nepolak commented 1 week ago

Fixed some tests, results of which were dependent on the platform used.

Fixed ReactiveProperty race condition

Also (seems to be) mentioned in https://github.com/Cysharp/R3/issues/229

neuecc commented 1 week ago

I understand that using a lock is the most reliable approach. However, for ReactiveProperty (and Subject), I want to avoid using locks. I'd like to know the conditions under which race conditions occur, and based on that, choose a better solution.

nepolak commented 1 week ago

I understand that using a lock is the most reliable approach. However, for ReactiveProperty (and Subject), I want to avoid using locks. I'd like to know the conditions under which race conditions occur, and based on that, choose a better solution.

That's understandable.

It may occur like this:

  1. Observer calls Subscribe on a ReactiveProperty, receives current value, but is not subscribed yet. It stays here: https://github.com/Cysharp/R3/blob/4fc537d03444c102f323abd2242852be59f1c7b6/src/R3/ReactiveProperty.cs#L213
  2. In the mean time, from another thread, OnNext is being called and a new value is written and pushed without synchronization: https://github.com/Cysharp/R3/blob/4fc537d03444c102f323abd2242852be59f1c7b6/src/R3/ReactiveProperty.cs#L116
  3. Observer is subscribed: https://github.com/Cysharp/R3/blob/4fc537d03444c102f323abd2242852be59f1c7b6/src/R3/ReactiveProperty.cs#L225

And so, although the items were pushed like this:

  1. First (e.g. from the constructor)
  2. Second

What the observer sees is:

  1. First

The 'Second' is left missing, and so observer thinks the current value is First. This is depicted in the log in this comment (third run): https://github.com/Cysharp/R3/issues/229#issue-2372532001