.NET Reverse Semaphore?

2019-01-23 12:52发布

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 complete before the program terminates. This leads me to believe I should increment something when a download starts, and decrement it when it finishes. But then how do I wait until the count is 0 again?

Semaphores sort of work in the opposite way in that you block when there are no resources available, not when they're all available (blocks when count is 0, rather than non-zero).

8条回答
干净又极端
2楼-- · 2019-01-23 13:33

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.

...

查看更多
别忘想泡老子
3楼-- · 2019-01-23 13:35

Looks like System.Threading.WaitHandle.WaitAll might be a pretty good fit:

Waits for all the elements in the specified array to receive a signal.

查看更多
登录 后发表回答