Семафор реверса.NET?

Возможно, это слишком поздно вечером, но я не могу думать о хорошем способе сделать это.

Я запустил набор асинхронных загрузок, и я хочу ожидать, пока они все не завершаются, прежде чем программа завершается. Это приводит меня полагать, что я должен увеличить что-то, когда загрузка запускается, и постепенно уменьшите ее, когда она заканчивается. Но затем как я ожидаю, пока количество не 0 снова?

Вид семафоров работы противоположным способом в этом, которое Вы блокируете, когда нет никаких доступных ресурсов, не, когда они все доступны (блоки, когда количество 0, а не ненулевое).

22
задан 14 revs, 2 users 100% 21 November 2016 в 16:31
поделиться

5 ответов

Проверьте класс CountdownLatch в этой статье журнала .

Обновление: теперь он входит в состав фреймворка с версии 4.0, Класс CountdownEvent.

.
14
ответ дан 29 November 2019 в 04:57
поделиться

Похоже, что System.Threading.WaitHandle.WaitAll может подойти:

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

8
ответ дан 29 November 2019 в 04:57
поделиться

Ну... вы можете схватить все семафорные счетчики на основном потоке, чтобы блокировать, когда счет равен 0, а не ненулевому .

REVISED: Здесь я предположил 3 вещи:

  • Пока программа запущена, новое задание на загрузку может начаться в любое время.
  • При выходе из программы, больше не будет никаких новых загрузок, о которых нужно позаботиться.
  • При выходе из программы, вам нужно подождать, пока все файлы закончат загрузку

Так что вот мое решение, пересмотренное:

Инициализирует Семафор достаточно большим счетчиком, так что вы никогда не достигнете максимума (это может быть просто 100 или просто 10 в зависимости от вашей ситуации):

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

Затем при каждой загрузке, начинается с WaitOne(), прежде чем начать загрузку, так что в случае выхода программы, никакие загрузки не могут начаться.

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

Затем, по завершении загрузки, освобождаем один счетчик (если бы мы его приобрели):

finally { _semaphore.Release(1); }

А затем, при событии "Выход", потребляют все счетчики на Семафоре:

for (var i = 0; i < maxDownloads; i++)
    _semaphore.WaitOne();

// all downloads are finished by this point.

...

...
4
ответ дан 29 November 2019 в 04:57
поделиться

Для каждого потока запускается Interlock.Increment a counter. И для каждого обратного вызова на финише потока, декрементируйте его.

Затем выполните цикл с Thread.Sleep(10) или что-то вроде того, пока счетчик не достигнет нуля.

.
0
ответ дан 29 November 2019 в 04:57
поделиться

В .NET 4 для этой цели имеется специальный тип CountdownEvent.

Или вы можете построить подобную вещь самостоятельно:

const int workItemsCount = 10;
// Set remaining work items count to initial work items count
int remainingWorkItems = workItemsCount;

using (var countDownEvent = new ManualResetEvent(false))
{
    for (int i = 0; i < workItemsCount; i++)
    {
        ThreadPool.QueueUserWorkItem(delegate
                                        {
                                            // Work item body
                                            // At the end signal event
                                            if (Interlocked.Decrement(ref remainingWorkItems) == 0)
                                                countDownEvent.Set();
                                        });
    }
    // Wait for all work items to complete
    countDownEvent.WaitOne();
}
10
ответ дан 29 November 2019 в 04:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: