Forma correcta de cerrar un socket UDP de locking

Tengo un objeto C ++ que crea un hilo para leer desde un socket UDP de locking:

mRunning.store(true); while (mRunning.load(boost::memory_order_consume)) { ... int size = recvfrom(mSocket, buf, kTextBufSize , 0, (struct sockaddr *) &packet->mReplyAddr.mSockAddr, (socklen_t*)&packet->mReplyAddr.mSockAddrLen); if (size > 0) { //do stuff } } return 0; 

(mRunning is a boost :: atomic) El destructor del objeto se llama desde otro hilo y hace esto:

 mRunning.store(false); #ifdef WIN32 if (mSocket != -1) closesocket(mSocket); #else if (mSocket != -1) close(mSocket); #endif pthread_join(mThread, NULL); 

Esto parece funcionar, pero uno de mis colegas sugirió que podría haber un problema si se interrumpe la recv en medio de la lectura de algo. ¿Es seguro este hilo? ¿Cuál es la forma correcta de cerrar un socket UDP de locking? (Debe ser multiplataforma OSX / Linux / Windows)

Podría haber muchos problemas diferentes. Al mover mi aplicación de una versión de FreeBSD a otra, encontré que cerca () funcionaba normalmente en el kernel anterior y simplemente colgaba cerca () hasta que algo regresó de recv () en la más nueva. Y OSX está basado en FreeBSD 🙂

La forma portátil de cerrar sockets desde diferentes hilos es crear tuberías y bloques no en recv (), sino en select (). Cuando necesite cerrar el zócalo, escriba algo en la tubería, seleccione () se desbloqueará y podrá hacerlo de forma segura ().

Bueno, la recvfrom en sí misma es segura para subprocesos. IIRC todas las funciones de socket son. La pregunta es:

  • ¿Qué sucederá si extrae el descriptor de debajo de la recvfrom mientras está copiando datos a su búfer?

Es una buena pregunta, pero dudo que el estándar diga algo sobre esto (también dudo que el manual específico de una implementación diga algo al respecto). Entonces cualquier implementación es libre de:

  • Complete la operación (tal vez porque ya no necesita el descriptor, o porque está haciendo un buen recuento de referencias o algo más)
  • Haga que la recvfrom falle y devuelva un -1 ( ENOTSOCK , EINVAL ?)
  • Falla espectacularmente porque los búferes y las estructuras internas de datos se liberan al close .

Obviamente, esto es solo una especulación ( muchas veces me he equivocado ), pero a menos que encuentre algo en el estándar para apoyar la idea de que puede cerrar el zócalo mientras lo recibe, no está seguro.

Entonces que puedes hacer ? Lo más seguro: use un mecanismo de sincronización para asegurarse de que solo close el socket después de que se realiza la recvfrom (semáforos, mutex, lo que sea).

Personalmente haría un UP en un semáforo después de la recvfrom y un DOWN antes del close .

Su colega tiene razón, los sockets de refuerzo no son seguros para hilos.

Sus opciones;

  1. Usa ASIO (haz esto)
  2. Tiempo de espera al bloquear la llamada. Esto no es realmente portátil, aunque podría funcionar.