Создание / открытие событий в C++ и проверка, запущены ли они

У меня есть два потока, которые используют событие для синхронизации. В каждом потоке они используют один и тот же вызов:

::CreateEvent( NULL,TRUE,FALSE,tcEventName )

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

Но когда SetEvent вызывается в потоке-производителе, то же событие никогда не запускается в потоке-потребителе (я использую WaitForMultipleObjects ())

Есть ли инструмент, который может сказать мне, действительно ли событие запускается должным образом.

Кроме того, когда я вызываю CreateEvent () в каждом потоке, возвращаемое значение дескриптора для каждого разное ... должны ли они быть одинаковыми?

Есть ли лучший способ сделать это, чтобы гарантировать, что это будет работать?

Это в Windows XP с использованием Visual Studio 2005

Изменить: я сделал еще несколько проверок и обнаружил, что вызов CreateEvent в потоке-производителе (второй для вызова CreateEvent) устанавливает LastError на 183 (ERROR_ALREADY_EXISTS), однако CreateEvent по-прежнему возвращает дескриптор события ... что дает? Как он может ошибаться как уже существующий, но все же возвращать дескриптор? Или он должен это делать?

Ответов (4)

Решение

Согласно документации MSDN для CreateEvent ,

Если функция завершается успешно, возвращаемое значение - дескриптор объекта события. Если именованный объект события существовал до вызова функции, функция возвращает дескриптор существующего объекта, а GetLastError возвращает ERROR_ALREADY_EXISTS.

Судя по вашему описанию, я не вижу проблем в том, что вы делаете. Я не вижу ничего, что указывало бы на то, что вы что-то делаете неправильно. Однако для меня я обычно создаю событие один раз, используя CreateEvent (), а затем передаю дескриптор потоку (-ам), о котором я хочу сигнализировать этим событием. Но в вашем подходе нет ничего технически неправильного.

Вы ведь понимаете, что WaitForMultipleObjects () возвращает индекс первого сигнализированного дескриптора в массиве дескрипторов, верно? Например, если ваше именованное событие является вторым в списке, но первый дескриптор сигнализируется большую часть времени (например, быстродействующим потоком или событием ручного сброса, которое сигнализируется, но никогда не сбрасывается), WaitForMultipleObjects () всегда будет возвращать WAIT_OBJECT_0. Другими словами, ваш потребительский поток никогда не увидит факт, что ваше именованное событие сигнализируется, потому что первый дескриптор сигнализируется «всегда». В этом случае поместите указанное событие первым в списке.

Вы случайно не установили для параметра bWaitAll функции WaitForMultipleObjects () значение TRUE, не так ли? Если вы это сделаете, то все дескрипторы в массиве дескрипторов будут сигнализированы до того, как функция вернется.

Кто вызывает ResetEvent () для указанного события? Это должен быть потребитель. Это не случайно вызвано каким-то сторонним потоком, не так ли?

Это просто некоторые вещи, которые нужно перепроверить. Если событие по-прежнему ведет себя не так, как вы ожидаете, замените WaitForMultipleObjects () на WaitForSingleObject (), чтобы проверить, правильно ли указанное событие сигнализирует потоку-потребителю.

Надеюсь это поможет.

Если вы просто используете несколько потоков в одном процессе, почему бы вам не передать дескриптор события от одного к другому? Насколько я знаю, именованные объекты ядра созданы для совместного использования их между процессами.

Также вы можете попробовать использовать функцию OpenEvent, чтобы открыть уже созданное событие. Это может дать некоторые идеи.

Ваш код должен работать так, как вы его описали. Если событие уже существует, когда вы пытаетесь его создать, вы получите дескриптор существующего события.

Ручки для каждого потока разные, поэтому вам не нужно беспокоиться, если они разные (они должны быть).

Я предлагаю вам немного упростить, чтобы увидеть, работает ли все так, как вы ожидаете. Тот факт, что вы используете WaitForMultipleObjects (), говорит мне, что у вас есть другие дела. Если вы думаете, что это не работает, избавьтесь от всего остального и посмотрите, сможете ли вы в этом разобраться.

В одном процессе вам нужно только один раз вызвать CreateEvent и поделиться дескриптором, возвращаемым во всех потоках.

Кроме того, вам не нужно называть событие, если вы не хотите, чтобы внешние процессы получали доступ к событию с помощью OpenEvent. Фактически, если вы назовете событие, только одна копия вашей программы сможет успешно вызвать CreateEvent.