using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading; namespace ScreenConnect; public abstract class ThreadQueue : ThreadRunner where TThreadRunContext : ThreadRunContext { private Queue queue; private int maxQueueSizeBeforeEnqueueBlocks; private bool clearQueueOnStartingAndStopped; protected ThreadQueue(CorePriority priority, bool rerunOnException, bool crashOnException, bool clearQueueOnStartingAndStopped, int maxQueueSizeBeforeEnqueueBlocks = -1) : base(priority, rerunOnException, crashOnException) { queue = new Queue(); this.clearQueueOnStartingAndStopped = clearQueueOnStartingAndStopped; this.maxQueueSizeBeforeEnqueueBlocks = maxQueueSizeBeforeEnqueueBlocks; } protected override void OnStarting() { base.OnStarting(); if (clearQueueOnStartingAndStopped) { ClearQueue(); } } protected override void OnStopped(bool wasUnexpected) { base.OnStopped(wasUnexpected); if (clearQueueOnStartingAndStopped) { ClearQueue(); } } protected int GetQueueDepthLockless() { return queue.Count; } protected TElement? TryDequeueItemIfAvailableLockless(ThreadRunContext runContext) { if (queue.Count == 0) { return default(TElement); } Monitor.PulseAll(runContext.SyncLock); return queue.Dequeue(); } protected TElement? TryDequeueItemIfAvailable(ThreadRunContext runContext) { lock (runContext.SyncLock) { return TryDequeueItemIfAvailableLockless(runContext); } } protected TElement? TryDequeueItem(ThreadRunContext runContext, Func? predicate = null, long? waitUntilMillisecondCount = null) { TryDequeueItem(runContext, out TElement item, predicate, waitUntilMillisecondCount); return item; } protected bool TryDequeueItem(ThreadRunContext runContext, [NotNullWhen(true)] out TElement? item, Func? predicate = null, long? waitUntilMillisecondCount = null) { lock (runContext.SyncLock) { while (!runContext.IsCancellationRequested) { if (queue.Count != 0) { if (predicate != null && !predicate(queue.Peek())) { item = default(TElement); return false; } Monitor.PulseAll(runContext.SyncLock); item = queue.Dequeue(); return true; } if (!waitUntilMillisecondCount.HasValue) { Monitor.Wait(runContext.SyncLock); continue; } long num = waitUntilMillisecondCount.Value - Singleton.Instance.GetMillisecondCount(); if (num <= 0) { break; } Singleton.Instance.WaitSafe(runContext.SyncLock, num); } } item = default(TElement); return false; } protected void ClearQueue() { lock (base.SyncLock) { queue.Clear(); Monitor.PulseAll(base.SyncLock); } } public void EnqueueItem(TElement item) { item.AssertArgumentNonNull("item"); lock (base.SyncLock) { while (base.IsRunning && maxQueueSizeBeforeEnqueueBlocks != -1 && queue.Count > maxQueueSizeBeforeEnqueueBlocks) { Monitor.Wait(base.SyncLock); } queue.Enqueue(item); Monitor.PulseAll(base.SyncLock); } } } public abstract class ThreadQueue : ThreadQueue { protected ThreadQueue(CorePriority priority, bool rerunOnException, bool crashOnException, bool clearQueueOnStartingAndStopped, int maxQueueSizeBeforeEnqueueBlocks = -1) : base(priority, rerunOnException, crashOnException, clearQueueOnStartingAndStopped, maxQueueSizeBeforeEnqueueBlocks) { } public override ThreadRunContext CreateThreadRunContext(object syncLock) { return new ThreadRunContext(syncLock); } }