Use simple IDisposable pattern.

This commit is contained in:
Stephen Kennedy 2019-11-05 15:42:38 +00:00
Родитель 907f034535
Коммит fa879ca991
3 изменённых файлов: 35 добавлений и 121 удалений

Просмотреть файл

@ -1,101 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
using System;
using System.Threading;
namespace Microsoft.MixedReality.Sharing.Utilities
{
/// <summary>
/// This is a base class for common IDisposable implementation.
/// </summary>
/// <remarks>Follows https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose </remarks>
public class DisposableBase : IDisposable
{
private string objectName;
private ThreadLocal<bool> insideDisposeFunction = new ThreadLocal<bool>(() => false);
/// <summary>
/// Is the current object disposed.
/// </summary>
public bool IsDisposed { get; private set; }
/// <summary>
/// The name of the current object.
/// </summary>
protected virtual string ObjectName => objectName ?? (objectName = GetType().Name);
~DisposableBase()
{
Dispose(false);
}
/// <summary>
/// Dispose the current object.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool isDisposing)
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
// If the finalizer is running, don't access the insideDisposeFunction, as it will
// also be finalizing.
if (isDisposing)
{
insideDisposeFunction = null;
}
else
{
insideDisposeFunction.Value = true;
}
try
{
if (isDisposing)
{
OnManagedDispose();
}
OnUnmanagedDispose();
}
finally
{
if (insideDisposeFunction != null)
{
insideDisposeFunction.Value = false;
}
}
}
/// <summary>
/// Override this method to dispose of managed objects.
/// </summary>
protected virtual void OnManagedDispose() { }
/// <summary>
/// Override this method to dispose of unmanaged objects.
/// </summary>
protected virtual void OnUnmanagedDispose() { }
/// <summary>
/// A helper method to throw if the current object is disposed.
/// </summary>
protected void ThrowIfDisposed()
{
if (insideDisposeFunction == null || (!insideDisposeFunction.Value && IsDisposed))
{
throw new ObjectDisposedException(ObjectName);
}
}
}
}

Просмотреть файл

@ -876,13 +876,14 @@ namespace Microsoft.MixedReality.Sharing.Matchmaking
/// <summary> /// <summary>
/// Simple discovery agent for local networks. /// Simple discovery agent for local networks.
/// </summary> /// </summary>
public class PeerDiscoveryAgent : DisposableBase, IDiscoveryAgent public class PeerDiscoveryAgent : IDiscoveryAgent
{ {
/// The transport for this agent. /// The transport for this agent.
private readonly IPeerDiscoveryTransport transport_; private readonly IPeerDiscoveryTransport transport_;
private Server server_; private Server server_;
private Client client_; private Client client_;
private Options options_; private Options options_;
private int disposed_ = 0;
// Counts how many things (local resources or discovery tasks) are using the transport. // Counts how many things (local resources or discovery tasks) are using the transport.
private int transportRefCount_ = 0; private int transportRefCount_ = 0;
@ -950,19 +951,22 @@ namespace Microsoft.MixedReality.Sharing.Matchmaking
} }
} }
protected override void OnUnmanagedDispose() public void Dispose()
{ {
server_?.Stop(); if( Interlocked.CompareExchange(ref disposed_, 1, 0) == 0 )
client_?.Stop();
// Give some time for the ByeBye message to be sent before shutting down the sockets.
// todo is there a smarter way to do this?
Task.Delay(1).Wait();
// Stop the network and prevent later disposals from trying to stop it again.
if (Interlocked.Exchange(ref transportRefCount_, 0) > 0)
{ {
transport_.Stop(); server_?.Stop();
client_?.Stop();
// Give some time for the ByeBye message to be sent before shutting down the sockets.
// todo is there a smarter way to do this?
Task.Delay(1).Wait();
// Stop the network and prevent later disposals from trying to stop it again.
if (Interlocked.Exchange(ref transportRefCount_, 0) > 0)
{
transport_.Stop();
}
} }
} }
} }

Просмотреть файл

@ -16,7 +16,7 @@ namespace Microsoft.MixedReality.SpatialAlignment
/// Helper base class for <see cref="ISpatialCoordinateService"/> implementations. /// Helper base class for <see cref="ISpatialCoordinateService"/> implementations.
/// </summary> /// </summary>
/// <typeparam name="TKey">They key for the <see cref="ISpatialCoordinate"/>.</typeparam> /// <typeparam name="TKey">They key for the <see cref="ISpatialCoordinate"/>.</typeparam>
public abstract class SpatialCoordinateServiceBase<TKey> : DisposableBase, ISpatialCoordinateService public abstract class SpatialCoordinateServiceBase<TKey> : ISpatialCoordinateService
{ {
/// <inheritdoc /> /// <inheritdoc />
public event Action<ISpatialCoordinate> CoordinatedDiscovered; public event Action<ISpatialCoordinate> CoordinatedDiscovered;
@ -29,9 +29,19 @@ namespace Microsoft.MixedReality.SpatialAlignment
private volatile bool isDiscovering = false; private volatile bool isDiscovering = false;
private volatile int discoveryOrCreateRequests = 0; private volatile int discoveryOrCreateRequests = 0;
private int isDisposed = 0;
protected readonly ConcurrentDictionary<TKey, ISpatialCoordinate> knownCoordinates = new ConcurrentDictionary<TKey, ISpatialCoordinate>(); protected readonly ConcurrentDictionary<TKey, ISpatialCoordinate> knownCoordinates = new ConcurrentDictionary<TKey, ISpatialCoordinate>();
protected void ThrowIfDisposed()
{
if (isDisposed != 0)
{
throw new ObjectDisposedException("SpatialCoordinateServiceBase");
}
}
/// <inheritdoc /> /// <inheritdoc />
public bool IsTracking public bool IsTracking
{ {
@ -55,15 +65,16 @@ namespace Microsoft.MixedReality.SpatialAlignment
} }
} }
protected override void OnManagedDispose() public void Dispose()
{ {
base.OnManagedDispose(); if (Interlocked.CompareExchange(ref isDisposed, 1, 0) == 0)
{
// Notify of dispose to any existing operations
disposedCTS.Cancel();
disposedCTS.Dispose();
// Notify of dispose to any existing operations knownCoordinates.Clear();
disposedCTS.Cancel(); }
disposedCTS.Dispose();
knownCoordinates.Clear();
} }
bool ISpatialCoordinateService.TryGetKnownCoordinate(string id, out ISpatialCoordinate spatialCoordinate) bool ISpatialCoordinateService.TryGetKnownCoordinate(string id, out ISpatialCoordinate spatialCoordinate)