Pregunta

¿Qué sucede si tengo un socket, s, no hay datos disponibles actualmente, es un socket de bloqueo, y llamo a recv desde dos hilos a la vez? ¿Uno de los hilos obtendrá los datos? ¿Lo conseguirán ambos? ¿La segunda llamada a <=> volverá con un error?

¿Fue útil?

Solución

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

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

Otros consejos

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

No puedo encontrar una referencia para esto, pero aquí lo entiendo:

La garantía de un proveedor de seguridad de subprocesos puede significar solo que múltiples subprocesos pueden usar de manera segura sus propios enchufes; no garantiza atomicidad en una sola llamada, y no promete ninguna asignación particular de los datos del socket entre múltiples hilos.

Suponga que el subproceso A llama a recv () en un socket que recibe transmisión de datos TCP a una velocidad alta. Si recv () necesita ser una llamada atómica, entonces el subproceso A podría bloquear la ejecución de todos los otros subprocesos, ya que necesita estar ejecutándose continuamente para extraer todos los datos (hasta que su búfer esté lleno, de todos modos). Eso no sería bueno. Por lo tanto, no asumiría que recv () es inmune al cambio de contexto.

Por el contrario, suponga que el hilo A hace una llamada de bloqueo a recv () en un socket TCP, y los datos ingresan 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 el hilo A todavía recibe datos. ¿Cuándo deja el hilo A de recibir datos para que el hilo B pueda comenzar a recibir datos? No conozco una implementación de Unix que intente recordar que el hilo A estaba en medio de una operación en el socket; en cambio, depende de la aplicación (hilos A y B) negociar su uso.

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

Desde la página del manual en recv

  

Un recv () en un socket SOCK_STREAM   devuelve tanta información disponible   como el tamaño del búfer suministrado puede   espera.

Supongamos que está utilizando TCP, ya que no se especificó en la pregunta. Supongamos que tiene el subproceso A y el subproceso B bloqueando ambos en recv () para el socket s. Una vez que s tenga algunos datos para recibir, 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 & Quot; mensaje & Quot ;, donde un mensaje es un concepto de nivel de aplicación.

El hilo 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 & Quot; mensaje & Quot; que estaba destinado para el hilo A. Estoy usando intencionalmente aquí.

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

Desearía poder decir que no sabía esto por experiencia.

Entonces, mientras que recv () es técnicamente seguro para subprocesos, es una mala idea tener dos subprocesos que lo llamen simultáneamente si lo está utilizando para TCP.

Hasta donde yo sé, es completamente seguro cuando está usando UDP.

Espero que esto ayude.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top