Как проверить наличие ожидающих потоков в замке - PullRequest
2 голосов
/ 12 октября 2011

Итак, я знаю, что вы можете использовать семафор и, возможно, другие методы, чтобы определить, будет ли блокировка успешной и / или сколько потоков ожидает блокировку, но можете ли вы сделать это из самой блокировки?

В моей ситуации есть обработчик событий, который может вызываться многими объектами в List.Я хочу сделать тест в замке, чтобы увидеть, все ли объекты находятся в правильном состоянии, прежде чем продолжить.Объекты переходят в соответствующее состояние , а затем вызывают это событие, поэтому в модели с одним потоком, когда последний вызывает это событие, все объекты будут в правильном состоянии, и мы продолжаем.Но мне пришло в голову, что с несколькими потоками несколько объектов могут быть переведены в состояние, которое я проверяю, но пока еще не обработали это событие, поскольку они ожидают блокировки.Поэтому проверка условного состояния в пределах блокировки будет истинной, но продолжение будет плохим, пока все потоки не завершат обработку этого события.Мне нужно, чтобы это было верно только в том случае, если последний поток обрабатывается, чтобы гарантировать, что мы не продолжим слишком быстро.

Например, в полуреалистичном коде:

object _LockObj = new object();

void Event_Handler(object sender, EventArgs e)
{
    MyObject originator = sender as MyObject;
    if(originator == null)
        return;

    *Do stuff with the originator*

    lock(_LockObj)
    {
        if(ListOfMyObjects.FindAll(o => o.State == DesiredState)
                          .Count == ListOfMyObjects.Count 
                                 && *nothing waiting at the lock*)
        {
            *Proceed*
        }
    }
}

Я отлично подготовленсогласиться с моим подходом - вонючее начало, и что решение, которое я ищу, является спорным, если я делаю это правильно, во-первых, но я не уверен, как сделать это правильно в многопоточном режиме.

Я собирался добавить еще несколько состояний в MyObject и управлять потоком, установив соответствующее состояние в разделе *Do stuff with the originator*, но было не правильно корректировать переход MyObject отсюда, не говоря уже оЗатем я должен реализовать состояние удержания для каждого состояния, которое вызывает событие, которое становится еще проще, а не просто!

Так что, если есть простой способ сделать ' ничего, ожидающего в замке «Тогда проверьте, что я бы хотел пойти по этому пути, если только не пропущен действительно простой для реализации шаблон, который помогает в этом сценарии.

Ответы [ 2 ]

3 голосов
/ 12 октября 2011

Во-первых, к сожалению, тестирование других потоков, ожидающих оператора lock (), не даст вам того, что вы хотите. Например, если объекты A, B и C перешли в желаемое состояние и вызвали свои события, возможно, что Event_Handler вызывается только для одного объекта, скажем, A в этой точке. Этот же обработчик будет работать для B и C в какой-то момент позже. Таким образом, все ваши объекты теперь предположительно находятся в желаемом состоянии, и никакие потоки не ожидают блокировки, но вы, вероятно, пытаетесь. не хочу "продолжать". Даже если вы это сделаете, вам нужно учесть, что то же самое может случиться через мгновение для B, а затем снова для C, поэтому «продолжить» может выполняться три раза ...

Это простое предложение, но вы можете использовать счетчик, чтобы проверить, сколько объектов действительно вызвало событие. Вы также можете использовать другой список, если счетчик не дает достаточной информации. Важной частью является то, что какой бы метод вы ни использовали, обновляйте только механизм счетчика / списка / другого, находясь внутри блокировки того же _LockObj. Затем, вероятно, сбросьте этот счетчик после выполнения continue . Если вам нужен доступ к счетчику где-то еще, убедитесь, что вы используете тот же lock(_LockObj), это гарантирует, что вы не измените его, находясь в другом критическом разделе.

object _LockObj = new object();
int _counter = 0;

void Event_Handler(object sender, EventArgs e)
{
    MyObject originator = sender as MyObject;
    if(originator == null)
        return;

    *Do stuff with the originator*

    lock(_LockObj)
    {
        ++_counter;
        if (_counter == ListOfMyObjects.Count)
        {
            *Proceed*

            _counter = 0;
        }
    }
}

Редактировать : Удалена избыточная проверка состояния объектов.

1 голос
/ 12 октября 2011

Задумывались ли вы о простой синхронной очереди рабочих элементов?Поэтому, когда событие вызывается, оно просто ставит в очередь обработку, и обработка выполняется по порядку отдельным потоком?

...