Example #1
0
        public static async Task WaitForAllMutexToCloseAsync()
        {
            DateTime start = DateTime.Now;

            lock (AsyncMutexesLock)
            {
                foreach (var mutex in AsyncMutexes)
                {
                    mutex.Value.IsQuitPending = true;
                }
            }

            while (true)
            {
                lock (AsyncMutexesLock)
                {
                    bool stillRunning = AsyncMutexes.Any(am => am.Value.IsAlive);
                    if (!stillRunning)
                    {
                        return;
                    }
                    Logger.LogDebug($"Waiting for: {string.Join(", ", AsyncMutexes.Where(am => am.Value.IsAlive).Select(m => m.Value.ShortName))}.");
                }
                await Task.Delay(200);

                if (DateTime.Now - start > TimeSpan.FromSeconds(60))
                {
                    var mutexesAlive = AsyncMutexes.Where(am => am.Value.IsAlive).Select(m => m.Value.ShortName);
                    var names        = string.Join(", ", mutexesAlive);
                    throw new TimeoutException($"{nameof(AsyncMutex)}(es) still alive after Timeout: {names}.");
                }
            }
        }
Example #2
0
        public AsyncMutex(string name)
        {
            // https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8
            // On a server that is running Terminal Services, a named system mutex can have two levels of visibility.
            // If its name begins with the prefix "Global\", the mutex is visible in all terminal server sessions.
            // If its name begins with the prefix "Local\", the mutex is visible only in the terminal server session where it was created.
            // In that case, a separate mutex with the same name can exist in each of the other terminal server sessions on the server.
            // If you do not specify a prefix when you create a named mutex, it takes the prefix "Local\".
            // Within a terminal server session, two mutexes whose names differ only by their prefixes are separate mutexes,
            // and both are visible to all processes in the terminal server session.
            // That is, the prefix names "Global\" and "Local\" describe the scope of the mutex name relative to terminal server sessions, not relative to processes.
            ShortName   = name;
            FullName    = $"Global\\4AA0E5A2-A94F-4B92-B962-F2BBC7A68323-{name}";
            Mutex       = null;
            MutexThread = null;

            // If we already have an asynclock with this fullname then just use it and do not create a new one.
            lock (AsyncMutexesLock)
            {
                if (AsyncMutexes.TryGetValue(FullName, out AsyncMutex asyncMutex))
                {
                    // Use the already existing lock.
                    AsyncLock = asyncMutex.AsyncLock;
                }
                else
                {
                    // Create a new lock.
                    AsyncLock = new AsyncLock();

                    AsyncMutexes.Add(FullName, this);
                }
            }
            ChangeStatus(AsyncLockStatus.StatusReady, AsyncLockStatus.StatusUninitialized);
        }
Example #3
0
        public static async Task WaitForAllMutexToCloseAsync()
        {
            var start = DateTimeOffset.UtcNow;

            lock (AsyncMutexesLock)
            {
                foreach (var mutex in AsyncMutexes)
                {
                    mutex.Value.IsQuitPending = true;
                }
            }

            var lastLog = DateTimeOffset.MinValue;
            var lastNumberOfAliveMutexes = 0;

            while (true)
            {
                KeyValuePair <string, AsyncMutex>[] asyncMutexes = null;
                lock (AsyncMutexesLock)
                {
                    asyncMutexes = AsyncMutexes.ToArray();
                }

                int numberOfAliveMutexes = asyncMutexes.Count(am => am.Value.IsAlive);
                if (numberOfAliveMutexes == 0)
                {
                    return;
                }

                // Log every 10 seconds or status change.
                if ((DateTimeOffset.UtcNow - lastLog) > TimeSpan.FromSeconds(10) || lastNumberOfAliveMutexes != numberOfAliveMutexes)
                {
                    Logger.LogDebug($"Waiting for: {string.Join(", ", asyncMutexes.Where(am => am.Value.IsAlive).Select(m => m.Value.ShortName))}.");
                    lastNumberOfAliveMutexes = numberOfAliveMutexes;
                    lastLog = DateTimeOffset.UtcNow;
                }

                await Task.Delay(100).ConfigureAwait(false);

                if (DateTimeOffset.UtcNow - start > TimeSpan.FromSeconds(60))
                {
                    var mutexesAlive = asyncMutexes.Where(am => am.Value.IsAlive).Select(m => m.Value.ShortName);
                    var names        = string.Join(", ", mutexesAlive);
                    throw new TimeoutException($"{nameof(AsyncMutex)}(es) still alive after Timeout: {names}.");
                }
            }
        }