public void Release(int releaseCount) { Debug.Assert(releaseCount > 0); Debug.Assert(releaseCount <= _maximumSignalCount); int countOfWaitersToWake; Counts counts = _separated._counts; while (true) { Counts newCounts = counts; // Increase the signal count. The addition doesn't overflow because of the limit on the max signal count in constructor. newCounts.AddSignalCount((uint)releaseCount); // Determine how many waiters to wake, taking into account how many spinners and waiters there are and how many waiters // have previously been signaled to wake but have not yet woken countOfWaitersToWake = (int)Math.Min(newCounts.SignalCount, (uint)counts.WaiterCount + counts.SpinnerCount) - counts.SpinnerCount - counts.CountOfWaitersSignaledToWake; if (countOfWaitersToWake > 0) { // Ideally, limiting to a maximum of releaseCount would not be necessary and could be an assert instead, but since // WaitForSignal() does not have enough information to tell whether a woken thread was signaled, and due to the cap // below, it's possible for countOfWaitersSignaledToWake to be less than the number of threads that have actually // been signaled to wake. if (countOfWaitersToWake > releaseCount) { countOfWaitersToWake = releaseCount; } // Cap countOfWaitersSignaledToWake to its max value. It's ok to ignore some woken threads in this count, it just // means some more threads will be woken next time. Typically, it won't reach the max anyway. newCounts.AddUpToMaxCountOfWaitersSignaledToWake((uint)countOfWaitersToWake); } Counts countsBeforeUpdate = _separated._counts.InterlockedCompareExchange(newCounts, counts); if (countsBeforeUpdate == counts) { Debug.Assert(releaseCount <= _maximumSignalCount - counts.SignalCount); if (countOfWaitersToWake > 0) { ReleaseCore(countOfWaitersToWake); } return; } counts = countsBeforeUpdate; } }