Hasta donde yo sé, una llamada de función actúa como una barrera del compilador, pero no como una barrera de la CPU.
Esta tutorial dice lo siguiente:
¡adquirir un bloqueo implica adquirir semántica, mientras que liberar un bloqueo implica liberar semántica! Todas las operaciones de memoria intermedias están contenidas dentro de un pequeño y agradable sándwich de barrera, lo que evita cualquier reordenación de memoria no deseada a través de los límites.
Supongo que la cita anterior se refiere al reordenamiento de la CPU y no al reordenamiento del compilador.
Pero no entiendo cómo un bloqueo y desbloqueo mutex hace que la CPU proporcione a estas funciones adquisición y liberación de semántica.
Por ejemplo, si tenemos el siguiente código C:
pthread_mutex_lock(&lock);
i = 10;
j = 20;
pthread_mutex_unlock(&lock);
El código C anterior se traduce en las siguientes (pseudo) instrucciones de ensamblaje:
push the address of lock into the stack
call pthread_mutex_lock()
mov 10 into i
mov 20 into j
push the address of lock into the stack
call pthread_mutex_unlock()
Ahora, ¿qué impide que la CPU se reordene? mov 10 into i
y mov 20 into j
por arriba call pthread_mutex_lock()
o hacia abajo call pthread_mutex_unlock()
?
si es el call
instrucción que evita que la CPU realice el reordenamiento, entonces, ¿por qué el tutorial que cité hace que parezca que son las funciones de bloqueo y desbloqueo de exclusión mutua las que impiden el reordenamiento de la CPU, por qué el tutorial que cité no decía que cualquier llamada de función evitará el reordenamiento de la CPU?
Mi pregunta es sobre la arquitectura x86.
¿Por qué no recuperó y editó su versión anterior de esto: stackoverflow.com/questions/50948788/…? Esta es la misma pregunta con ediciones menores, y el comentario de Martin aún se aplica.
– Peter Cordes
20 de junio de 2018 a las 14:52
“Supongo que la cita anterior se refiere al reordenamiento de la CPU y no al reordenamiento del compilador”. Ciertamente, bloquear/desbloquear un pthread mutex DEBE garantizar que el compilador no reordene las instrucciones que está protegiendo. Entonces, la cita habla sobre el reordenamiento del compilador y la CPU: son igualmente importantes desde el punto de vista de un pthread mutex.
– nos
20 de junio de 2018 a las 15:23
Es el implementaciones de
pthread_mutex_lock()
ypthread_mutex_unlock()
que se dan cuenta de sus promesas sobre el tiempo de ejecución de pedidos. Las CPU que realizan dicho reordenamiento también tienen instrucciones para modularlo, y las funciones de bloqueo/desbloqueo de mutex las usan (entre otras cosas).– John Bollinger
20 de junio de 2018 a las 16:26
Y ya voté a favor de su respuesta, @PeterCordes, y me negué a escribir una propia. Pero su respuesta está tan llena de información que, incluso con el resaltado, es fácil pasar por alto este punto, que creo que es el quid de la cuestión.
– John Bollinger
20 de junio de 2018 a las 18:23
Escribí mi respuesta porque, aunque la respuesta de @PeterCordes es excelente, pensé que esta pregunta también merecía una respuesta “pequeña” simplemente centrándome en lo limitado que pensé que estaba preguntando el OP: ¿cómo evita el compilador/tiempo de ejecución/implementación el reordenamiento de la CPU (no el compilador reordenación). La respuesta es simple: la implementación incluye barreras que impiden el reordenamiento de la CPU. El OP comentó mi respuesta que revela su malentendido original: ese reordenamiento podría ocurrir alrededor
call
como si fuera cualquier otra instrucción. no puede El reordenamiento ocurre contra el “rastreo dinámico”.– BeeOnRope
20 jun 2018 a las 19:25