¿Cout está sincronizado/seguro para subprocesos?

Resuelto edA-qa mort-ora-y asked hace 13 años • 4 respuestas

En general, asumo que las transmisiones no están sincronizadas, depende del usuario realizar el bloqueo adecuado. Sin embargo, ¿obtienen cosas como coutun trato especial en la biblioteca estándar?

Es decir, si se escriben varios subprocesos, ¿ coutpueden dañar el coutobjeto? Entiendo que incluso si estuviera sincronizado, aún obtendría una salida entrelazada aleatoriamente, pero ¿ese entrelazado está garantizado? Es decir, ¿es seguro usarlo coutdesde múltiples subprocesos?

¿Este proveedor depende? ¿Qué hace gcc?


Importante : proporcione algún tipo de referencia para su respuesta si dice "sí", ya que necesito algún tipo de prueba de ello.

Mi preocupación tampoco son las llamadas al sistema subyacente, están bien, pero las transmisiones agregan una capa de almacenamiento en búfer en la parte superior.

edA-qa mort-ora-y avatar Jun 16 '11 22:06 edA-qa mort-ora-y
Aceptado

El estándar C++03 no dice nada al respecto. Cuando no tiene garantías sobre la seguridad de los subprocesos de algo, debe tratarlo como si no fuera seguro para los subprocesos.

De particular interés aquí es el hecho de que coutestá amortiguado. Incluso si se garantiza que las llamadas a write(o cualquier cosa que logre ese efecto en esa implementación en particular) sean mutuamente excluyentes, el búfer podría ser compartido por los diferentes subprocesos. Esto conducirá rápidamente a la corrupción del estado interno de la corriente.

E incluso si se garantiza que el acceso al búfer es seguro para subprocesos, ¿qué crees que sucederá en este código?

// in one thread
cout << "The operation took " << result << " seconds.";

// in another thread
cout << "Hello world! Hello " << name << "!";

Probablemente desee que cada línea aquí actúe en exclusión mutua. Pero ¿cómo puede una implementación garantizar eso?

En C++11, tenemos algunas garantías. El FDIS dice lo siguiente en §27.4.1 [iostream.objects.overview]:

El acceso simultáneo a las funciones de entrada (§27.7.2.1) y salida (§27.7.3.1) de un objeto iostream estándar sincronizado (§27.5.3.4) o a un flujo C estándar por parte de múltiples subprocesos no dará lugar a una carrera de datos (§ 1.10). [Nota: Los usuarios aún deben sincronizar el uso simultáneo de estos objetos y transmisiones por parte de múltiples subprocesos si desean evitar caracteres entrelazados. - nota final]

Por lo tanto, no obtendrá transmisiones corruptas, pero aún así deberá sincronizarlas manualmente si no desea que la salida sea basura.

R. Martinho Fernandes avatar Jun 16 '2011 15:06 R. Martinho Fernandes

El estándar C++ no especifica si escribir en secuencias es seguro para subprocesos, pero normalmente no lo es.

www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging

y también: ¿ Los flujos de salida estándar en C++ son seguros para subprocesos (cout, cerr, clog)?

ACTUALIZAR

Eche un vistazo a la respuesta de @Martinho Fernandes para saber qué dice el nuevo estándar C++ 11 sobre esto.

phoxis avatar Jun 16 '2011 15:06 phoxis

Como mencionan otras respuestas, esto es definitivamente específico del proveedor, ya que el estándar C++ no menciona los subprocesos (esto cambia en C++ 0x).

GCC no hace muchas promesas sobre la seguridad de los subprocesos y la E/S. Pero la documentación de lo que promete está aquí:

  • http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html#manual.intro.using.concurrency.io

La clave es probablemente:

El tipo __basic_file es simplemente una colección de pequeños contenedores alrededor de la capa C stdio (nuevamente, vea el enlace en Estructura). No nos encerramos, sino que simplemente pasamos a las llamadas para abrir, escribir, etc.

Entonces, para 3.0, la pregunta "¿es seguro el subproceso múltiple para E/S?" debe responderse con "¿la biblioteca C de su plataforma es segura para E/S?" Algunos son predeterminados, otros no; muchos ofrecen múltiples implementaciones de la biblioteca C con diferentes compensaciones de seguridad y eficiencia de subprocesos. Usted, el programador, siempre debe tener cuidado con varios subprocesos.

(Como ejemplo, el estándar POSIX requiere que las operaciones de C stdio FILE* sean atómicas. Las bibliotecas C compatibles con POSIX (por ejemplo, en Solaris y GNU/Linux) tienen un mutex interno para serializar operaciones en FILE*. Sin embargo, aún necesita no hacer cosas estúpidas como llamar a fclose(fs) en un hilo seguido de un acceso a fs en otro).

Entonces, si la biblioteca C de su plataforma es segura para subprocesos, entonces sus operaciones de E/S de fstream serán seguras para subprocesos en el nivel más bajo. Para operaciones de nivel superior, como manipular los datos contenidos en las clases de formato de flujo (por ejemplo, configurar devoluciones de llamada dentro de un std::ofstream), es necesario proteger dichos accesos como cualquier otro recurso compartido crítico.

No sé si algo ha cambiado desde el período 3.0 mencionado.

La documentación de seguridad de subprocesos de MSVC iostreamsse puede encontrar aquí: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :

Un solo objeto es seguro para subprocesos para leer desde múltiples subprocesos. Por ejemplo, dado un objeto A, es seguro leer A desde el subproceso 1 y desde el subproceso 2 simultáneamente.

Si un subproceso escribe en un único objeto, todas las lecturas y escrituras de ese objeto en el mismo subproceso o en otros deben estar protegidas. Por ejemplo, dado un objeto A, si el subproceso 1 está escribiendo en A, entonces se debe impedir que el subproceso 2 lea o escriba en A.

Es seguro leer y escribir en una instancia de un tipo incluso si otro hilo está leyendo o escribiendo en una instancia diferente del mismo tipo. Por ejemplo, dados los objetos A y B del mismo tipo, es seguro si A se escribe en el hilo 1 y B se lee en el hilo 2.

...

Clases de iostream

Las clases de iostream siguen las mismas reglas que las demás clases, con una excepción. Es seguro escribir en un objeto desde varios subprocesos. Por ejemplo, el subproceso 1 puede escribir en cout al mismo tiempo que el subproceso 2. Sin embargo, esto puede provocar que la salida de los dos subprocesos se mezcle.

Nota: La lectura desde un búfer de flujo no se considera una operación de lectura. Debe considerarse como una operación de escritura, porque cambia el estado de la clase.

Tenga en cuenta que esa información es para la versión más reciente de MSVC (actualmente para VS 2010/MSVC 10/ cl.exe16.x). Puede seleccionar la información para versiones anteriores de MSVC usando un control desplegable en la página (y la información es diferente para las versiones anteriores).

Michael Burr avatar Jun 16 '2011 16:06 Michael Burr