public void AssignNullAfterDispose() { var d = new SingleAssignmentDisposable (); d.Dispose (); d.Disposable = null; // should not result in NRE, nor treated as if it assigned an instance. d.Disposable = Disposable.Create (() => {}); }
public void AssignNull() { var d = new SingleAssignmentDisposable (); d.Disposable = null; d.Disposable = null; // allowed (no effect) d.Disposable = Disposable.Create (() => {}); // should be allowed }
public void AssignMultipleTimes() { int i = 0, j = 0; var d = new SingleAssignmentDisposable (); d.Disposable = Disposable.Create (() => i++); d.Disposable = Disposable.Create (() => j++); }
public void AssignMultipleOnceAfterDispose() { var d = new SingleAssignmentDisposable (); d.Disposable = Disposable.Create (() => {}); d.Dispose (); d.Disposable = Disposable.Create (() => {}); }
/// <summary> /// Uses the double-indirection pattern to assign the disposable returned by the specified <paramref name="factory"/> /// to the <see cref="SerialDisposable.Disposable"/> property of the specified <paramref name="disposable"/>. /// </summary> /// <remarks> /// The double-indirection pattern avoids a race condition that can occur when the <paramref name="factory"/> /// has a side-effect that causes the <see cref="SerialDisposable.Disposable"/> property of the specified /// <paramref name="disposable"/> to be assigned before the <paramref name="factory"/> returns its disposable. /// This pattern ensures that the disposable returned by the <paramref name="factory"/> does not replace the /// disposable that was assigned by the <paramref name="factory"/>. /// </remarks> /// <param name="disposable">The object to which the disposable returned by the specified <paramref name="factory"/> is assigned.</param> /// <param name="factory">Returns an <see cref="IDisposable"/> that is assigned to the specified <paramref name="disposable"/>.</param> /// <seealso href="http://social.msdn.microsoft.com/Forums/en-IE/rx/thread/4e15feae-9c4c-4962-af32-95dde1420dda#4d5fe8c8-e5e8-4ee7-93ca-b48b6a56b8af"> /// Double indirection pattern example in Rx /// </seealso> public static void SetDisposableIndirectly(this SerialDisposable disposable, Func<IDisposable> factory) { Contract.Requires(disposable != null); Contract.Requires(factory != null); var indirection = new SingleAssignmentDisposable(); disposable.Disposable = indirection; indirection.Disposable = factory(); }
public static IDisposable Schedule(this IScheduler scheduler, ILiveValue<TimeSpan> interval, Action action) { var startTime = HiResTimer.Now(); var gate = new object(); var hasValue = false; var cancelable = new SerialDisposable(); var id = 0UL; var observer = interval.CreateObserver( o => Publish.OnConsume( () => { // get new interval var state = o.GetState(); // work out interval from here var timeSpan = TimeSpan.Zero; if (state.Status.IsConnected()) { timeSpan = state.NewValue - HiResTimer.ToTimeSpan(HiResTimer.Now() - startTime); if (timeSpan < TimeSpan.Zero) timeSpan = TimeSpan.Zero; } // adapted from Observable.Throttle() ulong currentid; lock (gate) { hasValue = true; id += 1UL; currentid = id; } var timer = new SingleAssignmentDisposable(); cancelable.Disposable = timer; timer.Disposable = scheduler.Schedule( timeSpan, () => { lock (gate) { if (hasValue && (id == currentid)) action(); hasValue = false; } }); }) ); interval.Subscribe(observer); return new CompositeDisposable(new IDisposable[] { observer, cancelable }); }
public Timer(TimeSpan dueTime, Action action) { _disposable = new SingleAssignmentDisposable(); _disposable.Disposable = Disposable.Create(Unroot); _action = action; _timer = new System.Threading.Timer(Tick, null, dueTime, TimeSpan.FromMilliseconds(System.Threading.Timeout.Infinite)); lock (s_timers) { if (!_hasRemoved) { s_timers.Add(_timer); _hasAdded = true; } } }
public void SingleAssignmentDisposable_DisposeAfterSet() { var disposed = false; var d = new SingleAssignmentDisposable(); var dd = Disposable.Create(() => { disposed = true; }); d.Disposable = dd; Assert.AreSame(dd, d.Disposable); Assert.IsFalse(disposed); d.Dispose(); Assert.IsTrue(disposed); d.Dispose(); Assert.IsTrue(disposed); Assert.IsTrue(d.IsDisposed); }
public void SingleAssignmentRxOfficial() { var d = new SingleAssignmentDisposable(); d.IsDisposed.IsFalse(); var id1 = new IdDisp(1); var id2 = new IdDisp(2); var id3 = new IdDisp(3); // dispose first d.Dispose(); d.IsDisposed.IsTrue(); d.Disposable = id1; id1.IsDisposed.IsTrue(); d.Disposable = id2; id2.IsDisposed.IsTrue(); d.Disposable = id3; id3.IsDisposed.IsTrue(); // normal flow d = new SingleAssignmentDisposable(); id1 = new IdDisp(1); id2 = new IdDisp(2); id3 = new IdDisp(3); d.Disposable = id1; id1.IsDisposed.IsFalse(); d.Dispose(); id1.IsDisposed.IsTrue(); d.Disposable = id2; id2.IsDisposed.IsTrue(); d.Disposable = id3; id3.IsDisposed.IsTrue(); // exception flow d = new SingleAssignmentDisposable(); id1 = new IdDisp(1); id2 = new IdDisp(2); id3 = new IdDisp(3); d.Disposable = id1; AssertEx.Catch<InvalidOperationException>(() => d.Disposable = id2); // null d = new SingleAssignmentDisposable(); id1 = new IdDisp(1); d.Disposable = null; d.Dispose(); d.Disposable = null; }
private static void Impl() { var rand = new Random(); for (int i = 0; i < 1000; i++) { var d = new SingleAssignmentDisposable(); var e = new ManualResetEvent(false); var cd = new CountdownEvent(2); var sleep1 = rand.Next(0, 1) == 0 ? 0 : rand.Next(2, 100); var sleep2 = rand.Next(0, 1) == 0 ? 0 : rand.Next(2, 100); ThreadPool.QueueUserWorkItem(_ => { Helpers.SleepOrSpin(sleep1); Console.Write("{DB} "); d.Dispose(); Console.Write("{DE} "); cd.Signal(); }); ThreadPool.QueueUserWorkItem(_ => { Helpers.SleepOrSpin(sleep2); Console.Write("{AB} "); d.Disposable = Disposable.Create(() => e.Set()); Console.Write("{AE} "); cd.Signal(); }); e.WaitOne(); cd.Wait(); Console.WriteLine("."); } }
private static void RefCountWithPost_(IEnumerable<Tuple<int, int>> parameters) { var worker = new Thread(() => { SynchronizationContext.SetSynchronizationContext(new MySyncCtx()); foreach (var p in parameters) { var N = p.Item1; var M = p.Item2; Console.Write("N = {0}, M = {1} - ", N, M); var bar = new Bar(); var foo = Observable.FromEventPattern<FooEventArgs>(h => { /*Console.Write("+");*/ bar.Foo += h; }, h => { bar.Foo -= h; /*Console.Write("-"); */}); var e = new ManualResetEvent(false); var cd = new CountdownEvent(M * 2); for (int i = 0; i < M; i++) { var f = new SingleAssignmentDisposable(); ThreadPool.QueueUserWorkItem(_ => { f.Disposable = foo.Subscribe(__ => { /*Console.Write("!");*/ }); cd.Signal(); }); ThreadPool.QueueUserWorkItem(_ => { f.Dispose(); cd.Signal(); }); } var hasObserved = 0; Console.Write("{SB}"); var d = foo.Subscribe(x => { // // [on BARTDE-M6500 with CPU and RAM pressure] // // Up to 8K concurrent observers, we typically don't see a time gap (expected worst-case behavior). // The code below uses an event to check the desired behavior of eventually tuning in to the event stream. // Console.Write("&" + x.EventArgs.Qux); e.Set(); Interlocked.Exchange(ref hasObserved, 1); }); Console.Write("{SE}"); var t = new Thread(() => { Console.Write("{TB}"); var i = 0; while (Thread.VolatileRead(ref hasObserved) == 0) bar.OnFoo(i++); Console.Write("{TE}"); }); t.Start(); t.Join(); cd.Wait(); e.WaitOne(); d.Dispose(); Console.WriteLine("."); } }); worker.Start(); worker.Join(); }
private static void RefCount_(IEnumerable<Tuple<int, int>> parameters) { foreach (var p in parameters) { var N = p.Item1; var M = p.Item2; Console.Write("N = {0}, M = {1} - ", N, M); var bar = new Bar(); var foo = Observable.FromEventPattern<FooEventArgs>(h => { Console.Write("+"); bar.Foo += h; }, h => { bar.Foo -= h; Console.Write("-"); }); var res = new List<int>(); var n = 0; var e = new ManualResetEvent(false); var cd = new CountdownEvent(M * 2); for (int i = 0; i < M; i++) { var f = new SingleAssignmentDisposable(); ThreadPool.QueueUserWorkItem(_ => { f.Disposable = foo.Subscribe(__ => { Console.Write("!"); }); cd.Signal(); }); ThreadPool.QueueUserWorkItem(_ => { f.Dispose(); cd.Signal(); }); } Console.Write("{SB}"); var d = foo.Subscribe(x => { //Console.Write("&"); if (++n == N) e.Set(); res.Add(x.EventArgs.Qux); }); Console.Write("{SE}"); var t = new Thread(() => { Console.Write("{TB}"); for (int i = 0; i < N; i++) bar.OnFoo(i); Console.Write("{TE}"); }); t.Start(); t.Join(); cd.Wait(); e.WaitOne(); d.Dispose(); if (!res.SequenceEqual(Enumerable.Range(0, N))) { Console.WriteLine("Panic!"); break; } Console.WriteLine("."); } }
public void SingleAssignmentDisposable_DisposeBeforeSet() { var disposed = false; var d = new SingleAssignmentDisposable(); var dd = Disposable.Create(() => { disposed = true; }); Assert.IsFalse(disposed); d.Dispose(); Assert.IsFalse(disposed); Assert.IsTrue(d.IsDisposed); d.Disposable = dd; Assert.IsTrue(disposed); //Assert.IsNull(d.Disposable); // BREAKING CHANGE v2 > v1.x - Undefined behavior after disposal. d.Disposable.Dispose(); // This should be a nop. d.Dispose(); Assert.IsTrue(disposed); }
public void SingleAssignmentDisposable_SetNull() { var d = new SingleAssignmentDisposable(); d.Disposable = null; }
public void SingleAssignmentDisposable_SetMultipleTimes() { var d = new SingleAssignmentDisposable(); d.Disposable = Disposable.Empty; ReactiveAssert.Throws<InvalidOperationException>(() => { d.Disposable = Disposable.Empty; }); }
public void SchedulePeriodic() { var evt = new ManualResetEvent(false); var id = Thread.CurrentThread.ManagedThreadId; var disp = DispatcherHelpers.EnsureDispatcher(); var sch = new DispatcherScheduler(disp); var d = new SingleAssignmentDisposable(); d.Disposable = sch.SchedulePeriodic(1, TimeSpan.FromSeconds(0.1), n => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); if (n == 3) { d.Dispose(); sch.Schedule(TimeSpan.FromSeconds(0.2), () => { Assert.AreNotEqual(id, Thread.CurrentThread.ManagedThreadId); evt.Set(); }); } if (n > 3) { Assert.Fail(); } return n + 1; }); evt.WaitOne(); disp.InvokeShutdown(); }
public void AssignOneThenNull() { var d = new SingleAssignmentDisposable (); d.Disposable = Disposable.Create (() => {}); d.Disposable = null; // this is not allowed }
public void Start(IHostController hostController) { AppHosting.SetupChannel(); var d = new SingleAssignmentDisposable(); if (keepAlive) { d.Disposable = Observable.Interval(TimeSpan.FromMilliseconds(500)) .Subscribe(i => { try { if (!hostController.isAlive()) { d.Dispose(); Process.GetCurrentProcess().Kill(); } } catch (Exception err) { dbg.Error(err); Process.GetCurrentProcess().Kill(); } }); } var live555 = new Live555(videoBuffer, metadataReceiver); live555.Play(mediaStreamInfo, playbackController); d.Dispose(); }
public void SchedulePeriodic_Nested() { var evt = new ManualResetEvent(false); var id = Thread.CurrentThread.ManagedThreadId; var lbl = CreateLabel(); var sch = new ControlScheduler(lbl); sch.Schedule(() => { lbl.Text = "Okay"; var d = new SingleAssignmentDisposable(); d.Disposable = sch.SchedulePeriodic(1, TimeSpan.FromSeconds(0.1), n => { lbl.Text = "Okay " + n; Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId); if (n == 3) { d.Dispose(); sch.Schedule(TimeSpan.FromSeconds(0.2), () => { Assert.Equal("Okay 3", lbl.Text); Assert.NotEqual(id, Thread.CurrentThread.ManagedThreadId); evt.Set(); }); } return n + 1; }); }); evt.WaitOne(); Application.Exit(); }
public IDisposable Play(MediaStreamInfo mediaStreamInfo, IPlaybackController playbackController) { //fix url var url = new Uri(mediaStreamInfo.url); if (url == null || !url.IsAbsoluteUri) { throw new Exception("Invalid playback url"); } if (mediaStreamInfo.transport != MediaStreamInfo.Transport.Http) { if (String.Compare(url.Scheme, "rtsp", true) != 0) { throw new Exception("Invalid playback url"); } } else if (String.Compare(url.Scheme, "rtsp", true) != 0) { int defPort; if (String.Compare(url.Scheme, Uri.UriSchemeHttp, true) == 0) { defPort = 80; } else if (String.Compare(url.Scheme, Uri.UriSchemeHttps, true) == 0) { defPort = 443; } else { throw new Exception("Invalid playback url"); } var ub = new UriBuilder(url); ub.Scheme = "rtsp"; if (ub.Port == -1) { ub.Port = defPort; } url = ub.Uri; mediaStreamInfo = new MediaStreamInfo(url.ToString(), mediaStreamInfo.transport, mediaStreamInfo.userNameToken); } var disposable = new SingleAssignmentDisposable(); playerTask.mediaStreamInfo = mediaStreamInfo; playerTask.playbackController = playbackController; if (playerHost != null) { playerHost.Dispose(); RemotingServices.Disconnect(playerHost); playerHost = null; } playerHost = new PlayerHost(playerTask); RemotingServices.Marshal(playerHost); var ipcChannel = AppHosting.SetupChannel(); var hostControllerUri = RemotingServices.GetObjectUri(playerHost); var hostControllerUrl = ipcChannel.GetUrlsForUri(hostControllerUri).First(); //start player host process var hostProcessArgs = new CommandLineArgs(); var t = Uri.EscapeDataString(hostControllerUrl); hostProcessArgs.Add("controller-url", new List<string> { hostControllerUrl }); var pi = new ProcessStartInfo() { FileName = Assembly.GetExecutingAssembly().Location, UseShellExecute = false, Arguments = String.Join(" ", hostProcessArgs.Format()), }; pi.EnvironmentVariables["PATH"] = String.Join("; ", Bootstrapper.specialFolders.dlls.Select(sfd => sfd.directory.FullName).Append(pi.EnvironmentVariables["PATH"])); StartHostProcess(pi); return Disposable.Create(() => { Dispose(); }); }