2012-06-09 17 views
5

Tengo un código que genera un pthread que intenta mantener una conexión de socket a un host remoto. Si alguna vez se pierde la conexión, intenta reconectarse usando una llamada de bloqueo connect() en su socket. Dado que el código se ejecuta en un hilo separado, realmente no me importa el hecho de que utiliza la API de socket síncrono.¿Cómo se interrumpe un hilo que realiza una conexión de socket de bloqueo?

Eso es, hasta que llega el momento de que mi aplicación salga. Me gustaría realizar una apariencia de apagado ordenado, así que uso primitivas de sincronización de subprocesos para activar el subproceso y señal para que salga, luego realice un pthread_join() en el subproceso para esperar a que se complete. Esto funciona muy bien, a menos que el hilo esté en el medio de una llamada connect() cuando ordeno el cierre. En ese caso, tengo que esperar a que termine el tiempo de conexión, lo que podría ser mucho tiempo. Esto hace que la aplicación parezca tardar mucho tiempo en apagarse.

Lo que me gustaría hacer es interrumpir la llamada al connect() de alguna manera. Después de que la llamada regrese, el hilo notará mi señal de salida y se apagará limpiamente. Como connect() es una llamada al sistema, pensé que podría interrumpirla intencionalmente usando una señal (haciendo que la llamada retornara a EINTR), pero no estoy seguro de si este es un método robusto en un entorno de subprocesos POSIX.

¿Alguien tiene alguna recomendación sobre cómo hacer esto, ya sea mediante el uso de señales o mediante algún otro método? Como nota, la llamada connect() está caída en algún código de biblioteca que no puedo modificar, por lo que cambiar a un socket no bloqueado no es una opción.

+2

También ponga una etiqueta de idioma. – Tudor

+0

Escribo en Python, pero no estoy buscando nada específico del idioma. Puedes asumir que estoy operando en Linux. –

+1

Cierre el zócalo. –

Respuesta

6

Trate de close() la toma de corriente para interrumpir el Connect(). No estoy seguro, pero creo que funcionará al menos en Linux. Por supuesto, tenga cuidado de sincronizar correctamente de manera que solo close() este socket una vez, o un segundo close() pueda cerrar teóricamente un descriptor de archivo no relacionado que se acaba de abrir.

EDITAR: apagado() puede ser más apropiado, ya que en realidad no cierra el socket.

O bien, es posible que desee echar un vistazo a pthread_cancel() y pthread_kill(). Sin embargo, no veo una forma de usar estos dos sin una condición de carrera.

Te aconsejo que abandones el enfoque de servidor de subprocesos múltiples y, en su lugar, actúes por eventos, por ejemplo, usando epoll para notificación de eventos. De esta forma puede evitar todos estos problemas básicos que se vuelven muy difíciles con los hilos, como el apagado correcto. Puedes hacer lo que quieras en cualquier momento, p. Ej. cierre con seguridad los enchufes y nunca más escuche de ellos.

Por otro lado, si en su subproceso de trabajo lo hace un no-bloqueo connect() y recibir una notificación a través de epoll_pwait() (o ppoll() o pselect(); tenga en cuenta el p), es posible que pueda evitar las condiciones de carrera asociadas con las señales.

+0

Gracias por la sugerencia de usar 'close()'; Voy a ver eso. Estoy de acuerdo en que un mecanismo impulsado por un evento sería mejor.Sin embargo, como señalé en mi pregunta, "la llamada' connect() 'está caída en algún código de biblioteca que no puedo modificar, por lo que cambiar a un socket que no sea de bloqueo no es una opción". –

+0

La parte "no se puede modificar" debería ser un gran problema aquí. Como noté, tenga cuidado de no cerrar dos veces; la biblioteca puede querer cerrarla() después de que connect() regrese. ¿Has considerado terminar el proceso por la fuerza cuando hayas terminado con todas tus cosas, asegurándote de que el código invasivo no se comporte mal hasta ese momento? –

+2

Fui con su sugerencia para usar 'shutdown()'. Dado que la biblioteca está escrita en Python, puedo echar un vistazo y obtener acceso al socket subyacente y posteriormente cerrarlo. Funciona bien. No es el mejor enfoque desde una perspectiva de arquitectura de software, pero funciona aquí, y tengo control sobre la versión de la biblioteca que se utilizará. –

Cuestiones relacionadas