.NET Reverse Semaphore?

后端 未结 8 1949
北荒
北荒 2020-12-15 17:21

Perhaps it\'s too late at night, but I can\'t think of a nice way to do this.

I\'ve started a bunch of asynchronous downloads, and I want to wait until they all comp

相关标签:
8条回答
  • 2020-12-15 18:12

    Based on the suggestions here, this is what I came up with. In addition to waiting until the count is 0, it will sleep if you spawn too many threads (count > max). Warning: This is not fully tested.

    public class ThreadCounter
    {
        #region Variables
        private int currentCount, maxCount;
        private ManualResetEvent eqZeroEvent;
        private object instanceLock = new object();
        #endregion
    
        #region Properties
        public int CurrentCount
        {
            get
            {
                return currentCount;
            }
            set
            {
                lock (instanceLock)
                {
                    currentCount = value;
                    AdjustZeroEvent();
                    AdjustMaxEvent();
                }
            }
        }
    
        public int MaxCount
        {
            get
            {
                return maxCount;
            }
            set
            {
                lock (instanceLock)
                {
                    maxCount = value;
                    AdjustMaxEvent();
                }
            }
        }
        #endregion
    
        #region Constructors
        public ThreadCounter() : this(0) { }
        public ThreadCounter(int initialCount) : this(initialCount, int.MaxValue) { }
        public ThreadCounter(int initialCount, int maximumCount)
        {
            currentCount = initialCount;
            maxCount = maximumCount;
            eqZeroEvent = currentCount == 0 ? new ManualResetEvent(true) : new ManualResetEvent(false);
        }
        #endregion
    
        #region Public Methods
        public void Increment()
        {
            ++CurrentCount;
        }
    
        public void Decrement()
        {
            --CurrentCount;
        }
    
        public void WaitUntilZero()
        {
            eqZeroEvent.WaitOne();
        }
        #endregion
    
        #region Private Methods
        private void AdjustZeroEvent()
        {
            if (currentCount == 0) eqZeroEvent.Set();
            else eqZeroEvent.Reset();
        }
    
        private void AdjustMaxEvent()
        {
            if (currentCount <= maxCount) Monitor.Pulse(instanceLock);
            else do { Monitor.Wait(instanceLock); } while (currentCount > maxCount);
        }
        #endregion
    }
    
    0 讨论(0)
  • 2020-12-15 18:26

    Well... you can snatch all the semaphore counters on the main thread back in order to blocks when count is 0, rather than non-zero.

    REVISED: Here I assumed 3 things:

    • While the program is running, a new download job may start at any time.
    • On exiting the program, there will be no more new downloads that needs taken care of.
    • On exiting the program, you need to wait for the all the files to finish downloading

    So here's my solution, revised:

    Initializes the Semaphore with a large enough counter so you never hit the maximum (it could be simply 100 or just 10 depending on your situation):

    var maxDownloads = 1000;
    _semaphore = new Semaphore(0, maxDownloads);
    

    Then on each downloads, begins with WaitOne() before starting the download so that in the event of program exiting, no downloads can start.

    if (_semaphore.WaitOne())
        /* proceeds with downloads */
    else
        /* we're terminating */
    

    Then on download completion, release one counter (if we had acquired one):

    finally { _semaphore.Release(1); }
    

    And then on the "Exit" event, consume up all the counters on the Semaphore:

    for (var i = 0; i < maxDownloads; i++)
        _semaphore.WaitOne();
    
    // all downloads are finished by this point.
    

    ...

    0 讨论(0)
提交回复
热议问题