From 6d895430b9da1f563e0bc4da8478d9c0eda8e2fc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:06:39 +0000 Subject: [PATCH 1/2] Initial plan From fd7111078508a165dcc0bc2c1a341407a2870e94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:13:22 +0000 Subject: [PATCH 2/2] Fix major bugs: thread safety, null reference, and race conditions Agent-Logs-Url: https://github.com/mvdhorstclb/SmartThreadPool/sessions/8aeaa823-abd2-483b-852a-1448ff0933aa Co-authored-by: mvdhorstclb <9461671+mvdhorstclb@users.noreply.github.com> --- SmartThreadPool/SmartThreadPool.cs | 7 ++++- SmartThreadPool/SynchronizedDictionary.cs | 8 ++++- SmartThreadPool/WorkItemsGroup.cs | 37 ++++++++++++++--------- SmartThreadPool/WorkItemsQueue.cs | 9 ++++-- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/SmartThreadPool/SmartThreadPool.cs b/SmartThreadPool/SmartThreadPool.cs index dc067a5..921cfb1 100644 --- a/SmartThreadPool/SmartThreadPool.cs +++ b/SmartThreadPool/SmartThreadPool.cs @@ -902,7 +902,7 @@ internal static void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItems ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, workItem); if ((null != workItemsGroup) && (null != workItem) && - CurrentThreadEntry.CurrentWorkItem.WasQueuedBy(workItemsGroup)) + workItem.WasQueuedBy(workItemsGroup)) { throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it causes a deadlock"); } @@ -1474,6 +1474,11 @@ public static bool IsWorkItemCanceled { get { + if (CurrentThreadEntry == null || CurrentThreadEntry.CurrentWorkItem == null) + { + throw new InvalidOperationException( + "IsWorkItemCanceled can only be called from a work item executing in the SmartThreadPool"); + } return CurrentThreadEntry.CurrentWorkItem.IsCanceled; } } diff --git a/SmartThreadPool/SynchronizedDictionary.cs b/SmartThreadPool/SynchronizedDictionary.cs index 9572a58..d0e472d 100644 --- a/SmartThreadPool/SynchronizedDictionary.cs +++ b/SmartThreadPool/SynchronizedDictionary.cs @@ -16,7 +16,13 @@ public SynchronizedDictionary() public int Count { - get { return _dictionary.Count; } + get + { + lock (_lock) + { + return _dictionary.Count; + } + } } public bool Contains(TKey key) diff --git a/SmartThreadPool/WorkItemsGroup.cs b/SmartThreadPool/WorkItemsGroup.cs index 14740fd..0a1ee0b 100644 --- a/SmartThreadPool/WorkItemsGroup.cs +++ b/SmartThreadPool/WorkItemsGroup.cs @@ -115,11 +115,14 @@ public override int Concurrency { Debug.Assert(value > 0); - int diff = value - _concurrency; - _concurrency = value; - if (diff > 0) + lock (_lock) { - EnqueueToSTPNextNWorkItem(diff); + int diff = value - _concurrency; + _concurrency = value; + if (diff > 0) + { + EnqueueToSTPNextNWorkItem(diff); + } } } } @@ -165,14 +168,17 @@ public override WIGStartInfo WIGStartInfo /// public override void Start() { - // If the Work Items Group already started then quit - if (!_isSuspended) + lock (_lock) { - return; + // If the Work Items Group already started then quit + if (!_isSuspended) + { + return; + } + _isSuspended = false; + + EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); } - _isSuspended = false; - - EnqueueToSTPNextNWorkItem(Math.Min(_workItemsQueue.Count, _concurrency)); } public override void Cancel(bool abortExecution) @@ -219,12 +225,15 @@ private void RegisterToWorkItemCompletion(IWorkItemResult wir) public void OnSTPIsStarting() { - if (_isSuspended) + lock (_lock) { - return; + if (_isSuspended) + { + return; + } + + EnqueueToSTPNextNWorkItem(_concurrency); } - - EnqueueToSTPNextNWorkItem(_concurrency); } public void EnqueueToSTPNextNWorkItem(int count) diff --git a/SmartThreadPool/WorkItemsQueue.cs b/SmartThreadPool/WorkItemsQueue.cs index 8eaf593..fb727b0 100644 --- a/SmartThreadPool/WorkItemsQueue.cs +++ b/SmartThreadPool/WorkItemsQueue.cs @@ -582,11 +582,14 @@ public void Dispose() public void Dispose() { - if (!_isDisposed) + lock (this) { - Cleanup(); + if (!_isDisposed) + { + Cleanup(); + _isDisposed = true; + } } - _isDisposed = true; } private void ValidateNotDisposed()