Безопасно ли «дважды закрывать» ручку с помощью CloseHandle? - PullRequest
6 голосов
/ 05 июля 2010

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

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

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

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

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

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

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

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

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

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

Спасибо!

John

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

Ответы [ 3 ]

12 голосов
/ 05 июля 2010

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

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 или любым другим сочетанием.

4 голосов
/ 05 июля 2010

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

1 голос
/ 05 июля 2010

Может произойти две вещи:

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

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

...