2012-02-20 29 views
56

que tienen un programa simple:tenedor() y la salida

int main() 
{ 
    std::cout << " Hello World"; 
    fork(); 
} 

Después de que el programa se ejecuta mi salida es: Hello World Hello World. ¿Por qué sucede esto en lugar de un solo Hello world? Supongo que el proceso secundario se vuelve a ejecutar detrás de escena y que el búfer de salida se comparte entre los procesos o algo similar, pero ¿es ese el caso o algo más está sucediendo?

+2

Esto es lo que fork genera el proceso con la memoria del padre. http://linux.die.net/man/2/fork – v01d

+2

Seguramente han habido muchas preguntas sobre 'fork()' últimamente ... hmm ... – Mysticial

+4

Huelo entrevistas: p –

Respuesta

91

Esto no es exactamente lo que pensaste originalmente. El búfer de salida no se comparte: cuando ejecuta la bifurcación, ambos procesos obtienen una copia del mismo búfer. Entonces, después de la bifurcación, ambos procesos finalmente lavan el búfer e imprimen los contenidos en la pantalla por separado.

Esto solo ocurre porque cout está almacenado temporalmente IO. Si usó cerr, que no está almacenado en el búfer, solo debería ver el mensaje una vez, antes del tenedor.

+6

Esto solo ocurre porque cout es IO con buffer de espacio de usuario.^_ ^ –

9

Si utiliza:

std::cout << " Hello World" << std::flush; 

Sólo se ve uno. Supongo que fork() copia cualquier buffer de salida std::cout escribe en.

6

La cadena no se escribe inmediatamente en la pantalla; en cambio, está escrito en un buffer interno. El proceso secundario hereda una copia del búfer de salida, por lo que cuando se vacía automáticamente el cout del niño, se imprime Hello World en la pantalla. El padre también imprime Hello World.

Si vacía cout antes del fork(), el problema desaparecerá casi con seguridad.

+1

No diría que el análisis es el correcto. El proceso secundario no es "repetir detrás de escena". –

+0

@MichaelMior: tienes razón. Me perdí el bit de "volver a ejecutar". He editado el idioma. – NPE

43

salida estándar utiliza IO con búfer. Cuando se llama al fork(), la salida estándar no se vacía y el contenido almacenado se replica en el proceso hijo. Estos búferes se vacían cuando sale el proceso, lo que da como resultado las dos salidas que ve.

Si cambia el programa para:

std::cout << " Hello World;" << std::endl; 

debería ver sólo una.

+2

esta respuesta me aclara todo. Muchas gracias dos veces – Tebe

17

Porque llamó a fork() sin enjuagar primero todos los buffers.

cout.flush(); 
fork(); 
2

Lo que probablemente vea aquí es un efecto del almacenamiento en búfer. En general, la salida se almacena en el búfer hasta que se vacía de manera explícita o implícitamente con una acción como la salida de una nueva línea. Debido a que la salida está almacenada en el búfer, ambas copias del proceso bifurcado tienen una salida tamponada y, por lo tanto, ambas lo muestran al finalizar el proceso y vaciar la memoria intermedia

10

El código de salida "Hello World" solo se ejecuta una vez. El problema es que el búfer de salida no se vacía. Entonces cuando se bifurca el proceso, "Hello World" todavía está sentado en el búfer de salida. Cuando ambos programas salgan, sus búferes de salida se vacían y verá la salida dos veces.

La forma más fácil de demostrar esto es agregando una nueva línea al final de la cadena, lo que causará un enrojecimiento implícito, o explícitamente al ras con std::cout.flush();. Entonces solo verás la salida una vez.

3

El motivo es que al invocar std::cout<< no realiza realmente la salida en sí, pero los datos se dejan en un búfer en el sistema. Cuando haces la bifurcación, se copian el código y los datos, así como todos los búferes asociados. Finalmente, tanto el padre como el hijo los descargan a la salida estándar y, por lo tanto, ve el resultado duplicado.