Безопасно ли дважды закрывать дескриптор с помощью CloseHandle?

Каковы последствия вызова CloseHandle более одного раза?

В документах сказано, что «вы не должны», но я думаю, что у меня есть реалистичный случай с именованными каналами, где дескриптор может быть закрыт извне (см. Конец сообщения).

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

(Вежливая просьба: пожалуйста, избегайте ответа "просто не надо!" :-). Конечно, следует избегать закрытия ручек более одного раза, и, конечно же, есть хорошие методы, помогающие в этом: мне просто интересно, что произойдет, если вы этого не сделаете).

Я слышал, что некоторые люди предполагают, что если дескриптор быстро повторно используется ОС, вы можете закрыть другой, другой дескриптор.

Это вероятно?

Как Windows выбирает идентификаторы дескрипторов?

Есть ли какая-либо гарантия относительно того, как часто будет повторно использоваться значение дескриптора?

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

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

Спасибо!

Джон

(Контекст к этому: я использую именованные каналы в модели клиент/сервер. Мне кажется очень сложным гарантировать, что только одна сторона гарантированно закроет дескриптор, например, в случае сбоя/убийства процесса. Возможно, я ошибаюсь. , но, как мне кажется, образец кода MSDN позволяет клиенту закрыть общий дескриптор, а затем, когда сервер пытается его закрыть, он уже закрыт).


person John    schedule 05.07.2010    source источник
comment
Какой общий дескриптор вы имеете в виду? Каждый процесс должен создавать и собственный дескриптор (одного и того же) канала. Как дескриптор становится общим? Увы, ответ есть: просто не надо, но это потому, что дескриптор вообще не должен использоваться совместно.   -  person anton.burger    schedule 05.07.2010


Ответы (3)


Достаточно просто проверить:

HANDLE h = 0;
h = CreateMutex(NULL, TRUE, NULL);
printf("%X\n", h);
CloseHandle(h);
h = 0;
h = CreateMutex(NULL, TRUE, NULL);
printf("%X\n", h);

В моем WinXP x64 это произвело:

2E8
2E8

Вот и все.
В отличие от портов TCP, дескрипторы перерабатываются немедленно.

Повторите этот эксперимент с вашим любимым API или любым их сочетанием.

person shoosh    schedule 05.07.2010
comment
+1, Также дескриптор можно повторно использовать для объекта любого типа - может быть, мьютекс, может быть, что-то еще. Выполнение CloseHandle() дважды может иметь неожиданные последствия. - person sharptooth; 05.07.2010

Вероятно, у вас неправильное мысленное представление о трубке. У него два конца, каждый из которых представлен разным дескриптором. Да, CloseHandle нужно вызывать дважды, чтобы экземпляр канала исчез. Но поскольку это разные ручки, это никогда не может вызвать никаких проблем. Также обратите внимание, что экземпляры дескрипторов зависят от процесса. Даже если они имеют одинаковое значение в обоих процессах, они не ссылаются на одну и ту же конечную точку канала.

person Hans Passant    schedule 05.07.2010
comment
Хм, может быть, я неправильно понял. Но я определенно видел проблемы, когда клиент в канале закрывает канал, а сервер затем выдает недопустимое исключение дескриптора (в режиме отладки). - person John; 07.07.2010

Возможны две вещи:

  1. Вы закрываете дескриптор, открытый другим кодом. Это, вероятно, не повлияет на ваш код, но может иметь катастрофические последствия для другого кода.
  2. Если вы работаете с подключенным отладчиком, ваше приложение выйдет из строя, потому что ОС вызовет исключение, когда обнаружит, что закрывается недопустимый дескриптор.

Ни один из них не является особенно привлекательным ИМХО.

person ReinstateMonica Larry Osterman    schedule 05.07.2010