/// <summary> /// Calls <see cref="EnterBusy"/> then returns an instance of <see cref="DisposableValueToken"/> that will call <see cref="ExitBusy"/> when disposed. /// </summary> /// <remarks> /// <para>The returned token can be used in a using block to ensure correct enter/exit behaviour.</para> /// </remarks> /// <returns>A <see cref="DisposableValueToken"/> instance.</returns> /// <exception cref="System.ObjectDisposedException">Thrown if the object is disposed or being disposed.</exception> protected DisposableValueToken ObtainBusyToken() { #pragma warning disable 420 return(DisposeAssistant.ObtainBusyToken(this, _DisposedState, ref _BusyCount, this.ExitBusy)); #pragma warning restore 420 }
/// <summary> /// Disposes this object and all internal resources. /// </summary> public virtual void Dispose() { #pragma warning disable 420 DisposeAssistant.Dispose(this, ref _DisposedState, ref _BusyCount, (disposing) => this.Dispose(disposing)); #pragma warning restore 420 //int priorState = _DisposedState; //if (priorState == DisposedState) return; //If we are already disposed, do nothing. ////Wait until there is no work in progress on the object (via EnterBusy/ExitBusy) //System.Threading.SpinWait.SpinUntil //( // () => (System.Threading.Interlocked.CompareExchange(ref _BusyCount, int.MinValue, 0)) <= 0 //); //// Atomically set our state to 'disposing' but only if it's not already in that state. //// If it is already in a 'disposing' state, wait for the dispose to complete before //// returning to the caller. //System.Threading.SpinWait.SpinUntil //( // () => (priorState = System.Threading.Interlocked.CompareExchange(ref _DisposedState, DisposingState, UndisposedState)) != DisposingState //); //if (_DisposedState == DisposedState) return; //If someone else completed disposing the object, do nothing. //try //{ // Dispose(true); //} //finally //{ // //Call SuppressFinalize in case a derived class adds a finaliser. // //Ensure it is done in the finally block. We're unlikely to be disposed again, // //but if we are and we encountered an error last time, we're likely to get the // //same error again. Worse, we may also get the error when disposed from the // //finalizer thread, and throwing exceptions there is a bad idea (https://ericlippert.com/2015/05/18/when-everything-you-know-is-wrong-part-one/). // //Additionally, code in a finally block will also execute if a thread abort // //occurs on the executing thread. // GC.SuppressFinalize(this); // //Now mark the object as disposed rather than disposing, // System.Threading.Interlocked.Exchange(ref _DisposedState, DisposedState); //} }
/// <summary> /// Throws an <see cref="System.ObjectDisposedException"/> if the object is currently disposed, otherwise does nothing. /// </summary> /// <exception cref="ObjectDisposedException">Deliberately thrown if this object has been or is being disposed.</exception> protected void ThrowIfDisposed() { DisposeAssistant.ThrowIfDisposed(this, _DisposedState, _BusyCount); }
/// <summary> /// Reduces the count of current operations on the object, returning it to a non-busy state if no other work is in progress thereby allowing calls to <see cref="Dispose()"/> to complete. /// </summary> /// <seealso cref="EnterBusy"/> /// <seealso cref="ObtainBusyToken"/> /// <exception cref="System.ObjectDisposedException">Thrown if this object is already disposed or being disposed.</exception> protected void ExitBusy() { #pragma warning disable 420 DisposeAssistant.ExitBusy(this, _DisposedState, ref _BusyCount); #pragma warning restore 420 }