2009-03-18 8 views
10

¿Qué sucede si tengo un zócalo, s, no hay datos actualmente disponibles en él, es un zócalo de bloqueo y llamo al recv en dos hilos en ¿una vez? ¿Alguno de los hilos obtendrá los datos? ¿Ambos lo conseguirán? ¿La segunda llamada al recv devolverá con un error?Llamada recv() en el mismo zócalo de bloqueo de dos hilos

Respuesta

10

Un hilo lo tendrá, y no hay forma de saber cuál.

Esto no parece un diseño razonable. ¿Hay alguna razón por la que necesite dos hilos llamando al recv() en el mismo zócalo?

+0

no, lo estoy implementando para un proyecto y quería saber qué debería pasar – Claudiu

+0

lo pregunté porque no veo una buena razón para diseñarlo de esa manera. Uno de los beneficios de enhebrar es aislar cosas como enchufes para simplificar el manejo. Compartir lecturas en un socket entre hilos introduce mucha complejidad en su lugar. – dwc

+8

Leer desde el mismo socket desde dos hilos tiene sentido si es un socket UDP para un protocolo sin conexión como DNS. Cada subproceso luego funciona de manera independiente en las solicitudes entrantes. – bdonlan

3

Las implementaciones de socket deberían ser seguras para subprocesos, por lo que exactamente un subproceso debería obtener los datos cuando estén disponibles. La otra llamada debería simplemente bloquear.

3

no puedo encontrar una referencia para esto, pero aquí está mi entendimiento:

garantía de un proveedor de hilo de seguridad puede significar simplemente que varios subprocesos pueden utilizar con seguridad cada uno sus propias tomas; no garantiza atomicity en una sola llamada, y no promete ninguna asignación particular de los datos del socket entre varios hilos.

Supongamos que el subproceso A llama a recv() en un socket que está recibiendo transmisión de datos TCP a gran velocidad. Si recv() debe ser una llamada atómica, el hilo A podría bloquear la ejecución de todos los otros hilos, ya que debe ejecutarse continuamente para extraer todos los datos (hasta que el búfer esté lleno, de todos modos). Eso no sería así. bueno. Por lo tanto, no asumiría que recv() es inmune al cambio de contexto.

Por el contrario, suponga que el subproceso A realiza un bloqueando llamada a recv() en un socket TCP, y los datos están entrando lentamente. Por lo tanto, la llamada a recv() regresa con errno establecido en EAGAIN.

En cualquiera de estos casos, suponga que el hilo B llama a recv() en el mismo socket mientras que el hilo A aún está recibiendo datos. ¿Cuándo el hilo A deja de recibir datos para que el hilo B pueda comenzar a recibir datos? No sé de una implementación de Unix que intente recordar que el hilo A estaba en el medio de una operación en el socket; en cambio, depende de la aplicación (hilos A y B) negociar su uso.

En general, es mejor diseñar la aplicación para que solo uno de los hilos llame a recv() en un solo socket.

+0

Creo que estás equivocado sobre tus suposiciones aquí. recv() obtiene un paquete de datos y generalmente se usa con UDP, con TCP todavía obtiene un paquete de datos, pero a menos que sea muy cuidadoso en el lado del remitente, puede obtener el contenido de dos escrituras en un recv. –

+0

De acuerdo, acabo de consultar los documentos y es un poco más complicado que un paquete según las banderas, pero eso es lo que he observado como el caso habitual en las aplicaciones de Linux en las que he trabajado. –

+0

Los datagramas UDP son ciertamente más seguros que las secuencias TCP wrt threads. Sin embargo, no estoy seguro de que sean 100% seguras para hilos: si obtiene un EINTR (¿eso todavía sucede?), El hilo A vuelve de recv() prematuramente, lo que le da al hilo B la oportunidad de saltar. –

2

Desde el man page en recv

A recv() en un socket SOCK_STREAM vuelve mayor cantidad de información disponible como el tamaño de la memoria intermedia suministrado puede espera.

Supongamos que está utilizando TCP, ya que no se especificó en la pregunta. Entonces supongamos que tiene el hilo A y el hilo B bloqueando en recv() para socket s. Una vez que s tiene algunos datos para ser recibidos, desbloqueará uno de los hilos, digamos A, y devolverá los datos. Los datos devueltos serán de algún tamaño aleatorio en lo que a nosotros respecta. El subproceso A inspecciona los datos recibidos y decide si tiene un "mensaje" completo, donde un mensaje es un concepto de nivel de aplicación.

El subproceso A decide que no tiene un mensaje completo, por lo que vuelve a llamar a recv().PERO mientras tanto B ya estaba bloqueando en el mismo zócalo, y ha recibido el resto del "mensaje" que estaba destinado para el hilo A. Estoy usando vagamente aquí.

Ahora tanto el hilo A como el hilo B tienen un mensaje incompleto y, según cómo se escriba el código, descartar los datos como no válidos o causar errores extraños y sutiles.

Ojalá pudiera decir que no sabía esto por experiencia.

Por lo tanto, aunque recv() en sí mismo es técnicamente seguro para subprocesos, es una mala idea tener dos hilos que lo llamen simultáneamente si lo está utilizando para TCP.

Por lo que sé, es completamente seguro cuando está usando UDP.

Espero que esto ayude.

Cuestiones relacionadas