public void MultiThreadIsSafe() { using (var cts = new CancellationTokenSource(Utils.TestTimeoutMs)) { var delayedException = new Utils.DelayedException(); using (var svc1 = MakeAgent(1)) using (var svc2 = MakeAgent(2)) { for (int i = 0; i < 1000; ++i) { { var category = "DisposeInHandler" + i; svc1.PublishAsync(category, ""); svc2.PublishAsync(category, ""); IDiscoverySubscription sub = svc2.Subscribe(category); sub.Updated += delayedException.Wrap <IDiscoverySubscription>( subscription => { Assert.True(subscription.Resources.Count() >= 0); subscription.Dispose(); }); } { var category = "DisposeInOtherThread" + i; svc1.PublishAsync(category, ""); svc2.PublishAsync(category, ""); IDiscoverySubscription sub = svc2.Subscribe(category); Task.Delay(random_.Next(0, 200)).ContinueWith( delayedException.Wrap <Task>( _ => { Assert.True(sub.Resources.Count() >= 0); sub.Dispose(); })); } } } Thread.Sleep(200); delayedException.Rethrow(); } }
public void CanDisposeSubscriptions() { const string category1 = "CanDisposeSubscriptions1"; const string category2 = "CanDisposeSubscriptions2"; IDiscoverySubscription surviving; IDiscoverySubscription survivingInHandler; var handlerEntered = new ManualResetEvent(false); var agentDisposed = new ManualResetEvent(false); var delayedException = new Utils.DelayedException(); using (var cts = new CancellationTokenSource(Utils.TestTimeoutMs)) using (var publishingAgent = MakeAgent(1)) { publishingAgent.PublishAsync(category1, "", null, cts.Token).Wait(); publishingAgent.PublishAsync(category2, "", null, cts.Token).Wait(); var agent = MakeAgent(2); { bool subIsDisposed = false; var subDisposedEvent = new ManualResetEvent(false); agent.Subscribe(category1).Updated += delayedException.Wrap <IDiscoverySubscription>( sub => { // Tests for https://github.com/microsoft/MixedReality-Sharing/issues/83. if (sub.Resources.Any()) { // Dispose the task from its handler. sub.Dispose(); // The handler is not called after disposal. Assert.False(subIsDisposed); subIsDisposed = true; subDisposedEvent.Set(); } }); // Wait until the subscription is disposed before going on. WaitWithCancellation(subDisposedEvent, cts.Token); } var survivingDisposedEvent = new ManualResetEvent(false); surviving = agent.Subscribe(category1); { bool subIsDisposed = false; survivingInHandler = agent.Subscribe(category2); survivingInHandler.Updated += delayedException.Wrap <IDiscoverySubscription>( sub => { handlerEntered.Set(); // Wait until the agent is disposed by the main thread. WaitWithCancellation(agentDisposed, cts.Token); // Dispose the task from its handler. sub.Dispose(); // The handler is not called after disposal. Assert.False(subIsDisposed); subIsDisposed = true; survivingDisposedEvent.Set(); }); } // Wait until the handler is entered. WaitWithCancellation(handlerEntered, cts.Token); // Dispose the agent while in the handler. agent.Dispose(); // Signal the handler to go ahead and dispose the subscription. agentDisposed.Set(); // The resources in the other surviving subscription are cleared eventually. while (surviving.Resources.Any()) { Task.Delay(1).Wait(cts.Token); } // Dispose the other surviving subscription. surviving.Dispose(); WaitWithCancellation(survivingDisposedEvent, cts.Token); delayedException.Rethrow(); } }