2012-06-09 3 views
5

У меня есть код, который порождает pthread, который пытается поддерживать соединение сокетов с удаленным хостом. Если соединение когда-либо потеряно, он пытается повторно подключиться с помощью блокирующего вызова connect() на свой сокет. Поскольку код работает в отдельном потоке, мне все равно, что он использует синхронный сокет API.Как прервать поток, выполняющий соединение блокирующего сокета?

То есть, пока наступит время для моего приложения для выхода. Я хотел бы выполнить некоторое подобие упорядоченного выключения, поэтому я использую примитивы синхронизации потоков, чтобы разбудить поток и подать сигнал для его выхода, а затем выполнить pthread_join() в потоке, чтобы дождаться его завершения. Это отлично работает, если поток не находится в середине вызова connect(), когда я командую выключение. В этом случае я должен ждать подключения к тайм-ауту, что может быть длительным. Это заставляет приложение работать долгое время, чтобы закрыть его.

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

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

+2

Также укажите языковой тег. – Tudor

+0

Я на самом деле пишу на Python, но я не ищу ничего, что зависит от языка. Можно предположить, что я работаю в Linux. –

+1

Закройте розетку. –

ответ

6

Попробуйте закрыть() гнездо для прерывания connect(). Я не уверен, но я думаю, что это будет работать, по крайней мере, на Linux. Конечно, будьте осторожны, чтобы синхронизировать правильно так, чтобы вы только close() этот сокет один раз или второй close() мог теоретически закрыть несвязанный файловый дескриптор, который был только что открыт.

EDIT: выключение() может быть более целесообразным, поскольку он фактически не закрывает сокет.

В качестве альтернативы, вы можете взглянуть на pthread_cancel() и pthread_kill(). Однако я не вижу способа использовать эти два без условия гонки.

Советуем отказаться от подхода с многопоточным сервером и вместо этого управлять событиями, например, используя epoll для уведомления о событиях. Таким образом, вы можете избежать всех этих очень простых проблем, которые становятся очень трудными для потоков, например, для правильного отключения. Вы в любое время можете делать все, что захотите, например. безопасно закрыть розетки и никогда не услышать от них снова.

С другой стороны, если в вашем рабочем потоке вы делаете нелипкая подключения() и получать уведомления через epoll_pwait() (или ppoll() или pselect(); обратите внимание на р), вы можете избежать условий гонки, связанных с сигналами.

+0

Спасибо за предложение использовать 'close()'; Я посмотрю на это. Я согласен с тем, что механизм, управляемый событиями, будет лучше.Однако, как я заметил в своем вопросе, «вызов« connect() »не работает в некотором библиотечном коде, который я не могу изменить, поэтому переход на неблокирующий сокет не является вариантом». –

+0

Часть «не может изменить» должна быть большой проблемой. Как я заметил, будьте осторожны, чтобы не закрывать дважды; библиотека может захотеть закрыть() после того, как функция connect() вернется. Вы считали, что просто завершите процесс силой, когда закончите со всеми своими вещами, убедившись, что инвазивный код не ошибается до этого момента? –

+2

Я пошел с вашим предложением использовать 'shutdown()'. Поскольку библиотека написана на Python, я могу заглянуть и получить доступ к базовому сокету и впоследствии закрыть его. Это работает хорошо. Не лучший подход с точки зрения архитектуры программного обеспечения, но он работает здесь, и у меня есть контроль над версией библиотеки, которая будет использоваться. –

Смежные вопросы