Существует ли метод WaitOne, который сначала вызывает метод Reset? - PullRequest
2 голосов
/ 05 ноября 2010

Я использую AutoResetEvent, где для события может быть сделано несколько вызовов Set (обработка исключений).Бывают случаи, когда вызывается дополнительный Set, поэтому, когда код выполняет второй вызов события WaitOne, он просто проходит сквозь него, потому что ворота уже открыты.

Решение состоит в том, чтобы вызвать Reset прямо передWaitOne.Есть ли более чистое решение или это единственный способ сделать это?Пример кода:

private void DoSomeWork()
{
    Thread thrd = new Thread(new ThreadStart(DoSomeOtherStuff));
    thrd.Start();

    //mEvt.Reset();
    mEvt.WaitOne();

    //continue with other stuff
}

private void DoSomeOtherStuff()
{
    /* lots of stuff */

    mEvt.Set();
}

private void ExceptionTriggerNeedsToBreakOutOfDoSomeWork()
{
   mEvt.Set();
}

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

Мое решение состоит в том, чтобы всегда вызывать Reset до WaitOne.Это достойное решение, плохой дизайн или есть другой тип события, которое будет обрабатывать этот сценарий?

РЕДАКТИРОВАТЬ: я только что переместил комментарий Reset (предлагаемое решение) рядом с событием.

Ответы [ 2 ]

4 голосов
/ 05 ноября 2010

Это не реальная проблема, вызов WaitOne () автоматически сбрасывает событие.В конце концов, вы использовали AutoResetEvent, а не ManualResetEvent.Ключевая фраза здесь - «Автосброс».

Наблюдение за тем, как оно проходит прямо через вызов WaitOne (), тоже вполне нормально.У вас хороший многоядерный процессор, поток начался сразу же после того, как вы вызвали Start (), и потребовалось всего несколько микросекунд, чтобы выполнить работу.Миллисекунды, что угодно, быстрее, чем мгновение ока.

Возможно, что еще важнее, вам просто не нужна нить здесь.Начинать один, потом ждать, пока он закончится, бессмысленно.Просто вызовите DoSomeOtherStuff () напрямую.

2 голосов
/ 06 ноября 2010

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

В идеале вы должны иметь блок try..catch..finally и вызывать Set () в блоке finally, а ваша обработка исключений не будет распределена по методам. Это работает для вас?

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

Меня также беспокоит, что вы вызываете набор более одного раза ... означает ли это, что при вызове первого набора ресурс действительно должен оставаться заблокированным? Если вы все еще можете нажать Set () во второй раз, для меня это говорит о том, что вы все еще выполняете код, который работает с общими ресурсами. В этом случае вы не хотите, чтобы вызов WaitOne () разблокировался.

Также обратите внимание, из MSDN:

Нет никакой гарантии, что каждый вызов метода Set освободит поток. Если два вызова находятся слишком близко друг к другу, так что второй вызов происходит до освобождения потока, освобождается только один поток. Как будто второго звонка не произошло.

В любом случае кажется, что ваш код должен либо идти по пути выдачи исключения, либо выполняться до завершения, но не оба. И.Е. Вы не должны вызывать Set () дважды.

...