2013-09-19 2 views
18

Что говорят POSIX и другие стандарты о ситуации, когда несколько потоков выполняют poll() или select(), вызывает однократное обращение к одному сокету или трубке?несколько потоков, выполняющих опрос() или select() на одном сокете или трубке

Если какие-либо данные поступают, просыпается только один из ожидающих потоков или просыпаются все ожидающие потоки?

ответ

15

Интересный вопрос ... Я прочитал текущий POSIX и не нашел конкретного ответа, т. Е. Нет спецификации о параллельных вызовах. Итак, я объясню, почему я считаю, что стандарт означает, что все проснется.

Соответствующая часть text для select/pselect является:

После успешного завершения, pselect() или выберите() функция должна изменить объекты на который указывает readfds, writefds и errorfds аргументы, чтобы указать, какой файл дескрипторов готовы для чтения, готовы к записи, или находятся в состоянии ошибки в ожидании, соответственно, [...]

и позже

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

в короткой (в случае чтения только), мы можем понять, как это:

select не блокирует это означает, что следующий вызов функции входа с O_NONBLOCK не возвращает ошибку с errno==EWOULDBLOCK. [Обратите внимание, что «следующая» - это моя интерпретация вышеизложенного.]

Если кто-то допускает эту интерпретацию, то два одновременных вызова select могут возвращать тот же FD, что и для чтения. На самом деле, даже если они не являются параллельными, но первый поток вызывает select, причем некоторый FD является читаемым, а затем, например,, read, второй поток, вызывающий select между двумя, может вернуть FD как читаемый для второго потока.

Теперь соответствующая часть для «просыпался» части вопроса заключается в следующем:

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

Здесь четко изложенная интерпретация предполагает, что все ожидающие вызовы возвратятся.

+0

Благодарим вас за исчерпывающий ответ. Я хочу, чтобы стандарт был более ясным. – wilx

+0

Действительно, хотелось бы этого. – subsub

2

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

Что должно делать select(), в соответствии с документацией POSIX, которая была приведена здесь, и моей простой 25-летней эксцессией с ней, заключается в возвращении числа FD, которые являются читаемыми, доступными для записи и т. Д., При этом мгновенное. Поэтому было бы совершенно неправильно для всех одновременных звонков , а не, чтобы все возвращали то же самое.

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

+1

Поскольку у вас нет намерения ответить на вопрос, почему вы не сделали это для комментариев? – sehe

+0

@EJP: Я тестирую, скажем, Linux ничего не говорит о, скажем, HP-UX. Мне нужен какой-то аргументированный ответ, а не эмпирический тест, если я могу его получить. – wilx

+0

@sehe Мне кажется, что я на самом деле ответил на вопрос, поэтому вторая часть вашего вопроса - это * non sequitur. * – EJP

4

Я только что нашел ошибку из-за этого вопроса: У меня есть два потока, выбирающих один и тот же сокет, и назовем accept, когда fd вернется как isset(). Фактически выбор возвращается для обоих потоков, fd isset() для этого fd в обоих потоках, и оба потока вызывают accept(), один выигрыш, а другие блоки ждут другого соединения, чтобы войти.

Итак, в выбор факта будет возвращаться во всех потоках, которые он блокирует для одного и того же fd.

+0

Это, безусловно, не удивительно. Например, поток A может выйти из select(), а затем до того, как у него будет возможность вызвать accept(), поток B может быть запланирован для запуска и отменить select() по той же причине, что и дескриптор в том же состоянии , Таким образом, теперь у вас есть оба потока, которые должны вызвать accept(). Вы всегда должны предполагать, что между одной частью кода и последующим будет бесконечно большой промежуток времени, имейте в виду, что любой другой процесс или поток могут работать в течение этого времени, и может ли это быть проблемой для вашего кода , – Nick

+1

Гравитация не удивительна, если вы знаете, как это работает. Но Ньютон нашел это удивительным. :-) – stu