Попытка выхода из блокировки чтения сокета UDP - PullRequest
3 голосов
/ 19 августа 2011

Этот вопрос похож на Правильный способ закрыть блокирующий UDP-сокет . У меня есть поток в C, который читает из сокета UDP. Чтение блокирует. Я хотел бы знать, возможно ли иметь возможность выхода из потока, не полагаясь на возврат recv ()? Например, можно ли закрыть сокет из другого потока и безопасно ожидать выхода из потока чтения сокета? В этой ветке не было ответа с высоким рейтингом, поэтому я спрашиваю его снова.

Ответы [ 5 ]

4 голосов
/ 19 августа 2011

Это действительно зависит от того, под какой системой вы работаете.Например, если вы работаете в POSIX-совместимой системе, и ваш поток отменяется, вызов recv () будет прерван при отмене потока, поскольку это точка отмены.

Если вы используетеВ более старой реализации сокетов вы могли установить обработчик сигнала для своего потока для чего-то вроде SIGUSR1 и надеяться, что никто другой не захочет этого и не подаст сигнал, поскольку recv () будет прерывать сигнал.Ваш лучший вариант - не блокировать, если это вообще возможно.

3 голосов
/ 19 августа 2011

Я не думаю, что закрытие сокета, участвующего в операции блокировки, является безопасным гарантированным способом завершения операции.Например, kernel.org мрачно предупреждает:

Возможно, неразумно закрывать файловые дескрипторы, когда они могут использоваться системными вызовами в других потоках в том же процессе.Поскольку файловый дескриптор может быть повторно использован, существуют некоторые непонятные условия гонки, которые могут вызвать непреднамеренные побочные эффекты.

  • Вместо этого вы можете использовать сигнал и заставить recv не работать с EINTR (убедитесь, что SA_RESTART не включен).Вы можете отправить сигнал определенному потоку с помощью pthread_kill

  • Вы можете включить SO_RCVTIMEO в сокете перед началом вызова recv

Лично я обычно стараюсь держаться подальше от всех мерзостей сигнала, но это жизнеспособный вариант.

2 голосов
/ 27 августа 2011

Вы не можете освободить общий ресурс, когда его использует или может использовать другой поток. На практике вы обнаружите, что даже не можете написать код, который бы делал то, что вы предлагаете.

Подумай об этом. Когда вы идете на вызов close, как вы можете узнать, что другой поток фактически заблокирован в recv? Что если он собирается вызвать recv, но другой поток вызывает socket и получает дескриптор, который вы только что закрыли? Теперь этот поток не только не обнаружит никакой ошибки, но и будет вызывать recv на сокете неправильный !

Вероятно, есть хороший способ решения вашей внешней проблемы, причина, по которой вам нужно выйти из блокирующего чтения сокета UDP. Есть также несколько уродливых хаков. Основной подход заключается в том, чтобы сделать сокет неблокирующим, и вместо того, чтобы блокировать чтение сокета UDP, имитируйте блокирующее чтение с select или poll. Затем вы можете прервать этот цикл несколькими способами:

Одним из способов является select тайм-аут и проверка флага 'abort', когда select возвращается.

Другой способ - также select на конце чтения канала. Отправьте один байт в канал, чтобы прервать select.

2 голосов
/ 19 августа 2011

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

Самый простой вариант - настроить таймер на прерывание собственного процесса через некоторое время, например, 30 секунд:

itimerval timer
timeval time;
time.tv_sec = 30;
time.tv_usec = 0;
timer.it_value = time;
if( setitimer( ITIMER_REAL, &timer, NULL ) != 0 )
  printf( "failed to start timer\n" );

Вы получитеSIGALRM по истечении указанного времени, что прервет вашу операцию блокировки и даст вам возможность повторить операцию или выйти.

1 голос
/ 06 декабря 2011

Если система совместима с posix, вы можете попытаться отслеживать вашу ветку: pthread_create с функцией, которая делает ваши recv и pthread_cond_signal сразу после, а затем возвращает.
Вызывающий поток создает pthread_cond_timedwait с желаемым временем ожидания и завершает вызываемый поток, если timed_out.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...