c - файловые - неправильный дескриптор файла linux



Что делает select(2), если вы закрываете(2) файловый дескриптор в отдельном потоке? (3)

Системный вызов select - это способ подождать, пока файловые дескрипторы изменят состояние, в то время как программам больше нечего делать. Основное применение - для серверных приложений, которые открывают кучу файловых дескрипторов, а затем ждут чего-нибудь, что им нужно (принимать новые подключения, читать запросы или отправлять ответы). Эти файловые дескрипторы будут открыты в неблокирующем режиме io, так что серверный процесс не будет висеть в syscall в любое время.

Это дополнительно означает, что нет необходимости в отдельных потоках, потому что вся работа, которая может быть выполнена в потоке, может быть выполнена до выбора вызова. И если работа занимает много времени, чем ее можно прервать, выберите вызов с тайм-аутом = {0,0}, обработчики дескрипторов файлов будут обработаны, а затем работа возобновится.

Теперь вы закрываете дескриптор файла в другом потоке. Почему у вас есть этот дополнительный поток вообще и почему он должен закрыть дескриптор файла?

В стандарте POSIX не указаны какие-либо намеки, что происходит в этом случае, поэтому то, что вы делаете, НЕ УТОЧНЕННОЕ ПОВЕДЕНИЕ. Ожидайте, что результат будет очень разным между различными операционными системами и даже между версией той же ОС.

С уважением, Бодо

Каково поведение функции select(2) когда дескриптор файла, который он просматривает для чтения, закрывается другим потоком?

Из некоторого беглого тестирования он сразу же возвращается. Я подозреваю, что результатом является либо то, что (а) он все еще продолжает ждать данных, но если вы на самом деле попытались прочитать из него, вы получите EBADF (возможно, есть потенциальная гонка) или (б), что он делает вид, будто файловый дескриптор никогда не передавался. Если последний случай верен, то передача в одном fd без тайм-аута может вызвать тупик, если он был закрыт.


Answer #1

Это немного запутывает то, что вы просите ...

Select () должен возвращаться после «интересного» изменения. Если close () просто уменьшил счетчик ссылок и файл все еще был открыт для записи где-то, тогда нет причины для select () для пробуждения.

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


Answer #2

По некоторым дополнительным исследованиям, кажется, что и dwc, и оба являются правильными.

Ответы обоих на вопрос сводятся к следующему: это неопределенное поведение. Это не означает, что это непредсказуемо обязательно, но разные ОС делают это по-другому. Похоже, что такие системы, как Solaris и HP-UX, возвращаются из select(2) в этом случае, но Linux не основан на этом сообщении в списке рассылки linux-kernel с 2001 года.

Аргумент в списке рассылки linux-kernel по существу состоит в том, что на него неопознано (и сломано) поведение. В случае Linux вызов close(2) в дескрипторе файла эффективно уменьшает количество ссылок на него. Так как есть вызов select(2) также со ссылкой на него, fd останется открытым и ожидает ввода до тех пор, пока не вернется select(2) . Это в основном ответ dwc . Вы получите событие в дескрипторе файла, а затем оно будет закрыто. Попытка прочитать из него приведет к EBADF, предполагая, что fd не был переработан. (Озабоченность, которую MarkR сделал в его ответе , хотя я думаю, что в большинстве случаев это возможно избежать с надлежащей синхронизацией.)

Так что спасибо всем за помощь.





posix