浏览代码

Merge pull request #247 from akarnokd/WithLatestFromFix

Fix WithLatestFrom potential memory visibility issues
Brendan Forster 9 年之前
父节点
当前提交
24eba2aca1
共有 1 个文件被更改,包括 22 次插入3 次删除
  1. 22 3
      Rx.NET/Source/System.Reactive.Linq/Reactive/Linq/Observable/WithLatestFrom.cs

+ 22 - 3
Rx.NET/Source/System.Reactive.Linq/Reactive/Linq/Observable/WithLatestFrom.cs

@@ -5,6 +5,7 @@
 #if !NO_PERF
 using System;
 using System.Reactive.Disposables;
+using System.Threading;
 
 namespace System.Reactive.Linq.ObservableImpl
 {
@@ -42,9 +43,12 @@ namespace System.Reactive.Linq.ObservableImpl
             private volatile bool _hasLatest;
             private TSecond _latest;
 
+            private object _latestGate;
+
             public IDisposable Run()
             {
                 _gate = new object();
+                _latestGate = new object();
 
                 var sndSubscription = new SingleAssignmentDisposable();
 
@@ -88,11 +92,19 @@ namespace System.Reactive.Linq.ObservableImpl
                 {
                     if (_parent._hasLatest) // Volatile read
                     {
+
+                        TSecond latest;
+
+                        lock (_parent._latestGate)
+                        {
+                            latest = _parent._latest;
+                        }
+
                         var res = default(TResult);
 
                         try
                         {
-                            res = _parent._parent._resultSelector(value, _parent._latest);
+                            res = _parent._parent._resultSelector(value, latest);
                         }
                         catch (Exception ex)
                         {
@@ -140,8 +152,15 @@ namespace System.Reactive.Linq.ObservableImpl
 
                 public void OnNext(TSecond value)
                 {
-                    _parent._latest = value;
-                    _parent._hasLatest = true; // Volatile write
+                    lock (_parent._latestGate)
+                    {
+                        _parent._latest = value;
+                    }
+
+                    if (!_parent._hasLatest)
+                    {
+                        _parent._hasLatest = true;
+                    }
                 }
             }
         }