2011-09-28 8 views
7

Veo a personas haciendo esto en algunas partes de los sistemas de aplicaciones multiproceso y multiproceso con los que trabajo. Parece que se hace alrededor de las líneas de depuración:¿Cuál es el efecto de llamar a suspensión (0) en un sistema UNIX?

std::cerr << "DEBUG: Reaching: " << __FUNCTION__ << " @ " << __LINE__ << std::endl; 
sleep(0); 

If macro out sleep (0); (es decir, cámbielo a ""), la salida de depuración del sistema parece venir en diferente orden (menos predecible), así que creo que hace que la línea salga antes, pero pensé que std :: cerr no estaba búfer, y std: : endl llama a std :: flush() de todos modos, entonces ¿por qué sería esto?

+0

Estaba a punto de decirle que lea la página del manual, pero la leí primero y no responde la pregunta. –

+1

pthread_yield de Pobre? – Nemo

+1

@Nemo, casi. Esto es efectivamente un rendimiento de todo el proceso de peso pesado; el control vuelve al programador del proceso. –

Respuesta

12

Básicamente, cede el control al planificador y le permite volver a programar al instante. Dicho esto, básicamente es un truco para tratar de engañar al sistema operativo para que haga algo.

Y nunca es una buena idea engañar al sistema operativo.

Si el sistema está adecuadamente subcargado, irse a dormir significa que el sistema operativo obtendrá el control y dejará que la cola de E/S se descargue, por lo que tendría ese efecto. A veces. Dependiente.

Exactamente lo que está haciendo depende de los detalles de la implementación que, francamente, no puede confiar.

0

Lo utiliza como una forma de permitir que se ejecuten otros procesos que pueden estar esperando algún tiempo de CPU, pero sin forzar un retraso particular si no hay otros procesos esperando para ejecutarse.

8

Interrumpe el programador de una manera difícil de predecir.

Normalmente, el resultado será similar a una llamada al pthread_yield() - renunciar a sus timesCells. El resultado de esto es que, bajo una gran carga de impresión de depuración, tendrá menos probabilidades de ser reemplazado en medio de la escritura en cerr (es decir, entre esos << s), ya que estará al comienzo de un lapso de tiempo después de la última impresión de depuración, y por lo tanto, es menos probable que tenga varios subprocesos sobrescribiendo el resultado de cada uno (es decir, obteniendo algo como DEBUG: REACHING: foo() @ DEBUG: REACHING bar()17 @ 24).

Dicho esto, este método no es confiable: está perturbando el programador, no solicitando semántica específica. También es lento: ingresa incondicionalmente en el kernel para ceder (y posiblemente rebotando control entre múltiples hilos con demasiada frecuencia). Y es menos probable que funcione correctamente en una CPU multinúcleo.

Sería mejor poner un mutex sobre todos los resultados de depuración de esta manera. Dicho esto, como se trata de un código de depuración, no es de extrañar que el autor haya utilizado un truco rápido y sucio para que funcione lo suficientemente bien como para solucionar cualquier problema que hayan tenido.

1

En la mayoría de las plataformas, sleep(0) hace que el planificador trate el hilo actual más o menos como si hubiera usado su ciclo de tiempo. Normalmente, esto significa que, si es posible, se programará otro subproceso en el mismo proceso en ese núcleo si uno está listo para ejecutarse. Como ha notado, tiende a hacer que la programación sea un poco más predecible. Para mí, eso parece contraproducente cuando se depura.

Estoy de acuerdo con el comentario de Nemo de que es casi lo mismo que pthread_yield. Tiene algunos usos legítimos, pero a veces se usa erróneamente como una forma de proporcionar más equidad o reducir la latencia. Por lo general, empeora el rendimiento porque un cambio de contexto destruye los cachés.

He mirado las otras respuestas y estoy de acuerdo con la sensación general de desconcierto.Mi apuesta es que no hay una buena razón para ello, aparte de que alguien pensó que una programación más predecible era algo bueno. (No lo es. La flexibilidad es buena. Cuantos más requisitos ponga en el planificador, más tendrá que sacrificar para cumplir esos requisitos. Si impone requisitos que realmente no son necesarios, puede cambiar el rendimiento por nada)

0

Como han mencionado otros, sleep(0) es una llamada al sistema que causa que el hilo actual renuncie al control de la CPU.

La única razón legítima para usar esto que puedo pensar es cuando se implementa una primitiva de sincronización propia como un bloqueo de giro usando instrucciones de ensamblador como LOCK (x86) y; LDREX y STREX (ARMv7). En tal caso, si encontramos un bloqueo, también deberíamos renunciar al control inmediatamente con la esperanza de que otro hilo haga lo suyo y desbloquee nuestro bloqueo. Esto definitivamente está girando hasta que nuestro segmento de tiempo haya terminado.

Habiendo dicho eso, realmente necesita saber lo que está haciendo al implementar su propia primitiva de sincronización. Específicamente, puede que tenga que poner barreras de memoria para imponer orden de lecturas y escrituras. Probablemente estés mucho mejor usando las primitivas provistas en la plataforma.

Cuestiones relacionadas