Может ли сокет быть закрыт из другого потока, когда происходит отправка / запись по тому же сокету?
Предположим, что один поток блокирует вызов recv, а другой поток закрывает этот сокет, будет ли поток в вызове recv знаете об этом и смело выходите?
Я хотел бы знать, будет ли поведение различаться в разных ОС / платформах. Если да, как он будет вести себя в Solaris?
Я не знаком с реализацией сетевого стека Solaris, но приведу свою теорию/объяснение того, почему он должен быть безопасным.
read(2)
для данного сокета. В буфере приема сокета нет данных, поэтому поток A снимается с процессора и помещается в очередь ожидания для этого сокета. Здесь не инициируются никакие события сетевого стека, состояние соединения (при условии, что TCP) не изменилось. close(2)
на сокете. Хотя структура сокета ядра должна быть заблокирована, пока поток B обращается к ней, ни один другой поток не удерживает эту блокировку (поток A снял блокировку, когда он был переведен в режим ожидания). Предполагая, что в буфере отправки сокета нет необработанных данных, отправляется пакет FIN
, и соединение переходит в состояние FIN WAIT 1
(опять же я предполагаю, что здесь TCP, см. состояние соединения диаграмма)FIN
, или в противном случае системный вызов вернется с eof
. В любом случае внутренние структуры ядра будут защищены от несанкционированного одновременного доступа. Это не означает, что рекомендуется выполнять ввод-вывод через сокеты из нескольких потоков. Я бы посоветовал обратить внимание на неблокирующие сокеты, конечные автоматы и фреймворки вроде libevent
.
Да, можно закрыть сокет из другого потока. Любые заблокированные/занятые потоки, использующие этот сокет, сообщат об соответствующей ошибке.