2009-10-01 11 views
5

que tiene una aplicación asíncrona ejecutar varios hilos que realizan operaciones a través de sockets donde se programan las operaciones y luego ejecutado de forma asíncrona.Evitar la reutilización del mismo número fd en una aplicación multi-hilo conector

Estoy intentando evitar una situación cuando una vez programada una operación de lectura sobre un socket, el socket se cierra y vuelve a abrir (posiblemente otro igual en otra operación) antes de que la primera operación comience a ejecutarse, lo que terminará leyendo el descriptor de archivo correcto pero el par incorrecto.

El problema viene porque (aceptar(); close(); aceptar()) devuelve el mismo fd en tanto acepta() que puede conducir a la situación anterior.

no veo una manera de evitarlo.

¿Alguna pista?

+0

¿Por qué el socket que se bloquea en un hilo está siendo cerrado por otro hilo? –

+0

esa es la naturaleza de un sistema asíncrono, una operación lee, otra escribe, otra puede cerrarse, y todas pueden ejecutarse en diferentes subprocesos. –

+2

reconsiderar su enfoque. por lo general, hay un solo hilo que acepta conexiones y engendra hilos para manejarlos. esos hilos son entonces responsables de cerrar la conexión, y ningún otro hilo llega incluso a acceder a esa conexión. –

Respuesta

3

Ok, encontré la respuesta.

La mejor manera aquí es llamar a accept() y obtener el fd más bajo disponible, duplicarlo con un número conocido por usted como dup2 (6,1000) y cerrar (6), ahora tiene el control del rango de fd tu usas.

Siguiente aceptamos vendrá de nuevo con 6 o similares, y vamos a dup2 (6999); y seguir disminuyendo así y reiniciarlo si es demasiado bajo.

Dado que la aceptación se realiza siempre en el mismo subproceso y dup2 y close no son caros en comparación con la aceptación que siempre se hace allí, es perfecto para mis necesidades.

2

¿Cómo se gestionan los enchufes? Parece que usted tiene múltiples hilos cualquiera de los cuales puede:

  1. accept una conexión entrante
  2. close una conexión existente
  3. hacer una nueva conexión saliente

Parece que usted necesita una manera de para mediar en el acceso a los diferentes enchufes que flotan alrededor. ¿Ha considerado asociar cada socket con mutex que evita cerrar el socket mientras todavía está en uso, o tal vez poner cada descriptor de socket en una estructura con un recuento de referencias atómicas que evitará que otros subprocesos lo cierren hasta que todos los hilos terminen de usarlo?

+0

Podría hacerlo de esa manera, pero agregar mutexes a este sistema casi sin bloqueo es algo que trato de evitar. Lo mejor sería garantizar que accept no dará fd secuencialmente, pero no puedo ver que eso suceda. –

+0

@Arkaitz - entonces la segunda solución que mencioné podría ser buena para ti. Mantenga el socket en una estructura con un contador de referencia y simplemente no permita que ningún hilo cierre un socket con un recuento de referencia superior a cero. Sin bloqueo, y el socket no se cierra hasta que todos los hilos hayan terminado. –

1

un socket es un 5-tupla {Local-addr, locales puertos, alejado-addr, remota puertos, proto}, por lo que si usted es capaz de utilizar estas propiedades en lugar de fd para el evento/manejador de enrutamiento que puede evitar el choque fd.

otra opción sería la de serializar todos cerca()/aceptar() Operaciones (prioridades?), De modo que no pueden entremezclar

+1

Todavía necesitaría mutexes para proteger esas estructuras, lo que ralentizará más el sistema, siendo una situación límite que estoy tratando de evitar bloquear allí. –

0

mantener un recuento de las operaciones pendientes (lectura/escritura, etc.) para cada socket y también si hay una solicitud de cierre pendiente en el socket. Donde antes habría llamado de cerca, verifique primero si hay alguna operación pendiente. Si los hay, llamada apagado en su lugar, y sólo se cierran cuando llame a las operaciones pendientes cuentan llega a 0.

1

Muy buena pregunta! Ni siquiera me di cuenta de que tal problema podría ocurrir.

La única respuesta que se me ocurre es que no debes Close() para señalar que un socket se termina. Una solución es usar shutdown() para terminar la conexión. Luego puede cerrar() el socket de forma segura mediante el recuento de referencias.

+0

La función 'close' disminuye el recuento de referencias de sockets en el sistema operativo subyacente,' shutdown' obliga a cerrar y envía un EOF/FIN al par. Consulte esta publicación de SO para obtener más detalles: http://stackoverflow.com/questions/409783/socket-shutdown-vs-socket-close/598759#598759 –

+0

Como se menciona en el enlace que publicó, shutdown() no cierra el socket , simplemente termina la comunicación. Shutdown() haría que falle cualquier operación de E/S pendiente (o futura), pero no desasignaría el FD, por lo que el problema descrito no ocurriría. En el caso de que una operación falle, el hilo que hace la operación disminuiría un recuento de referencia (que se había incrementado previamente cuando el hilo recibió el socket), si eso va cero cierra el socket. Obviamente, este recuento sería algo implementado en el programa, no el recuento del sistema operativo. – TrayMan

+0

Ni siquiera necesita preocuparse por el recuento de referencias, solo cierre el socket si falla la operación de lectura. – atomice

1

Todavía tendría cuidado de usar dup2() a un valor fd bien conocido. Recuerde que dup2() realizará un cierre en el objetivo antes de duplicar; eso podría entrar en conflicto con algún hilo no relacionado que realice E/S no relacionadas si comienza a tener 1000 archivos abiertos.

Si yo fuera usted, dadas las restricciones que está insistiendo, usaría dup() (no dup2()) dentro de un mutex. (Quizás mutexes por-fd si le preocupa eso).

+0

La cosa es accept & dup2 y todas se ejecutarán siempre en el mismo hilo. Así que podría pasar de MAX_FD a 10 o así y luego comenzar de nuevo, la posibilidad de dup2() ing un fd a MAX_FD cuando MAX_FD acaba de cerrarse porque comenzamos de nuevo no es realmente para tener en cuenta. –

+0

¿Pero puede probar que no está haciendo archivos abiertos no relacionados? ¿O tal vez alguna biblioteca lo está haciendo en tu nombre? ¿Y puedes probar que el recuento de FD de ocurrencia natural finalmente no llegará a 1000? Quizás puedas garantizar estas cosas, pero este tipo de cosas me pondrían nervioso con tu enfoque. – asveikau

Cuestiones relacionadas