private void ReleaseLock() { if (!IsAlive) { throw new InvalidOperationException("Thread should be alive."); } // On multiply call we will get an exception. This is not a dispose so we can throw here. ChangeStatus(AsyncLockStatus.StatusReleasing, AsyncLockStatus.StatusAcquired); StopThread(); ChangeStatus(AsyncLockStatus.StatusReady, AsyncLockStatus.StatusReleasing); // Release the local lock. AsyncLock?.ReleaseLock(); }
/// <summary> /// The Lock mechanism designed for standard using blocks. This lock is thread and interprocess safe. /// You can create and use it from anywhere. /// </summary> /// <param name="cancellationToken"></param> /// <param name="pollInterval">The frequency of polling the termination of the mutex-thread.</param> /// <returns>The IDisposable await-able Task.</returns> public async Task <IDisposable> LockAsync(CancellationToken cancellationToken = default, int pollInterval = 100) { Exception inner = null; try { if (IsQuitPending) { throw new OperationCanceledException($"{nameof(AsyncMutex)}.{nameof(AsyncMutex.LockAsync)} failed because quit is pending on: {ShortName}."); } // Local lock for thread safety. await AsyncLock.LockAsync(cancellationToken); if (IsAlive) { throw new InvalidOperationException("Thread should not be alive."); } MutexThread = new Thread(new ParameterizedThreadStart(HoldLock)) { Name = $"{nameof(MutexThread)}" }; MutexThread.Start(cancellationToken); ChangeStatus(AsyncLockStatus.StatusAcquiring, AsyncLockStatus.StatusReady); // Thread is running from now. try { // Create the mutex and acquire it. await SetCommandAsync(1, cancellationToken, pollInterval); } catch (Exception ex) { Logger.LogWarning(ex); // If the thread is still alive we must stop it StopThread(); ChangeStatus(AsyncLockStatus.StatusReady, AsyncLockStatus.StatusAcquiring); throw ex; } ChangeStatus(AsyncLockStatus.StatusAcquired, AsyncLockStatus.StatusAcquiring); return(new Key(this)); } catch (TaskCanceledException) { // Let it go. } catch (AbandonedMutexException) { // abandoned mutexes are still acquired, we just need // to handle the exception and treat it as acquisition Logger.LogWarning($"{nameof(AbandonedMutexException)} in {ShortName}."); return(new Key(this)); } catch (Exception ex) { Logger.LogError($"{ex.ToTypeMessageString()} in {ShortName}."); inner = ex; // Let it go. } // Release the local lock. AsyncLock.ReleaseLock(); throw new IOException($"Could not acquire system wide mutex on {ShortName}.", inner); }
/// <summary> /// Release the lock. /// </summary> public void Dispose() { _asyncLock.ReleaseLock(); }