¿Qué hace el «bloqueo» la enseñanza media en x86 asamblea?

Vi algunos x86 asamblea en Qt fuente:

q_atomic_increment:
    movl 4(%esp), %ecx
    lock 
    incl (%ecx)
    mov $0,%eax
    setne %al
    ret

    .align 4,0x90
    .type q_atomic_increment,@function
    .size   q_atomic_increment,.-q_atomic_increment
  1. De Google, no sabía lock la instrucción de la causa de la CPU para bloquear el bus, pero no sé cuando la CPU libera el bus?

  2. Sobre todo el código de arriba, no entiendo cómo este código implementa la Add?

InformationsquelleAutor gemfield | 2012-01-17

4 Kommentare

  1. 91
    1. LOCK no es una instrucción de sí mismo: es una instrucción de prefijo, que se aplica a la instrucción siguiente. Instrucción de que debe ser algo que se hace una lectura-modificación-escritura en memoria (INC, XCHG, CMPXCHG etc.) — en este caso es el incl (%ecx) instrucción que increments la long word a la dirección que se celebró en el ecx registro.

      La LOCK prefijo asegura que la CPU tiene la propiedad exclusiva de la correspondiente línea de caché para la duración de la operación, y ofrece ciertas garantías de orden. Esto puede lograrse mediante la afirmación de un autobús de la cerradura, pero la CPU evitar esto en lo posible. Si el autobús está bloqueado, entonces es sólo para la duración de la habitación cerrada la instrucción.

    2. Este código copias la dirección de la variable se incrementa la pila en el ecx registro, no hace lock incl (%ecx) atómicamente incremento de la variable en 1. Las siguientes dos instrucciones que establezca la eax registro (que tiene el valor de retorno de la función) a 0 si el nuevo valor de la variable es 0, y 1 en caso contrario. La operación es un incremento, no un complemento (de ahí el nombre).

    • Así que el instuction «mov $0,%eax» parece redundante?
    • No, el MOV establece el todo de EAX a cero. SETNE sólo cambia el byte bajo. Sin MOV, el 3 de alta bytes de EAX contendría al azar restos de valores de las operaciones anteriores, por lo que el valor de retorno sería incorrecta.
    • En uno de los de Rusia libro «Ensamblador para DOS, Windows и Linux, 2000. Sergei Zukkov» autor menciona lo siguiente acerca de este prefijo: «En todo el tiempo de la orden, siempre con ese prefijo, el bus de datos, será suspendido, y si un sistema tiene un procesador diferente, no puede acceder a la memoria hasta el final de la línea, con el prefijo de BLOQUEO. XCHG comando automáticamente siempre se realiza con el acceso a la memoria de la cerradura, incluso si el prefijo de BLOQUEO no se especifica. Este prefijo puede ser utilizado sólo con los comandos AGREGAR, ADC, Y, BTC, BTR, BTS, CMPXCHG, DEC, INC, NEG, NO, O, SBB, SUB, XOR, XADD y XCHG.»
    • las Cpu modernas son por tanto más eficiente: si los datos de un locked instrucción de no cruzar una línea de caché, un núcleo de la CPU puede sólo en el ámbito interno de la cerradura de que la línea de la memoria caché en lugar de bloquear todas las cargas/tiendas de todos los otros núcleos. Véase también mi respuesta en Puede num++ se atómica para ‘int num’? para obtener más detalles de cómo funciona esto de hacer aparecen atómica a los posibles observadores utilizando el MESI caché-coherencia de protocolo.
    • Muchas gracias! Genial! 🙂
  2. 12

    Lo que puede estar fallando a entender es que el microcódigo necesarios para incrementar un valor requiere que leemos en el antiguo valor de la primera.

    El Bloqueo de palabras clave de las fuerzas de las múltiples micro instrucciones que son en realidad ocurren a aparecer para operar de forma atómica.

    Si había 2 hilos cada uno tratando de incremento de la misma variable, y ambos leen el mismo valor original al mismo tiempo, ambos incremento para el mismo valor, y ambos escribir el mismo valor.

    Lugar de tener la variable se incrementa dos veces, que es la expectativa típica, se termina el incremento de la variable una vez.

    El bloqueo de palabras clave evita que esto suceda.

  3. 10

    De google, yo sabía de bloqueo de la instrucción de la causa de la cpu bloquear el bus,pero me
    no sé cuando la cpu libre el bus ?

    LOCK es una instrucción de prefijo, por lo tanto sólo se aplica a la siguiente instrucción, la fuente no la hace muy claro aquí, pero la verdadera enseñanza es LOCK INC. Así que el Autobús está bloqueado por el incremento, a continuación, desbloquear

    Sobre todo el código de arriba, no entiendo cómo estos código
    implementado el Complemento?

    No implementar un Complemento, que implementan un incremento, junto con un retorno de indicación si el valor era 0. Una adición usaría LOCK XADD (sin embargo, windows InterlockedIncrement/Decremento son también implementar con LOCK XADD).

    • Gracias! A continuación, el cual registro almacena el valor de la función(q_atomic_increment)’s el valor de retorno ?
    • valores de retorno se almacena en %eax
    • Así,el código: «volver q_atomic_increment(&_q_value) != 0» es para probar si %eax no es igual a cero ?
    • su cero d, entonces el LSB se establece a través de SETNE usando el condicional banderas de INC.
    • Es que si el edad valor era 0 o no que se devuelve en %eax (como la respuesta actualmente en estados unidos), o el nuevo valor?
    • es el nuevo valor de verdad. el inc establecer el cero de la bandera según el resultado de la inc, y no según las fuentes. ver: c9x.me/x86/html/file_module_x86_id_140.html

  4. 1

    Mínima ejecutable de C++ hilos + BLOQUEO de ensamblador ejemplo

    main.cpp

    #include <atomic>
    #include <cassert>
    #include <iostream>
    #include <thread>
    #include <vector>
    
    std::atomic_ulong my_atomic_ulong(0);
    unsigned long my_non_atomic_ulong = 0;
    unsigned long my_arch_atomic_ulong = 0;
    unsigned long my_arch_non_atomic_ulong = 0;
    size_t niters;
    
    void threadMain() {
        for (size_t i = 0; i < niters; ++i) {
            my_atomic_ulong++;
            my_non_atomic_ulong++;
            __asm__ __volatile__ (
                "incq %0;"
                : "+m" (my_arch_non_atomic_ulong)
                :
                :
            );
            __asm__ __volatile__ (
                "lock;"
                "incq %0;"
                : "+m" (my_arch_atomic_ulong)
                :
                :
            );
        }
    }
    
    int main(int argc, char **argv) {
        size_t nthreads;
        if (argc > 1) {
            nthreads = std::stoull(argv[1], NULL, 0);
        } else {
            nthreads = 2;
        }
        if (argc > 2) {
            niters = std::stoull(argv[2], NULL, 0);
        } else {
            niters = 10000;
        }
        std::vector<std::thread> threads(nthreads);
        for (size_t i = 0; i < nthreads; ++i)
            threads[i] = std::thread(threadMain);
        for (size_t i = 0; i < nthreads; ++i)
            threads[i].join();
        assert(my_atomic_ulong.load() == nthreads * niters);
        assert(my_atomic_ulong == my_atomic_ulong.load());
        std::cout << "my_non_atomic_ulong " << my_non_atomic_ulong << std::endl;
        assert(my_arch_atomic_ulong == nthreads * niters);
        std::cout << "my_arch_non_atomic_ulong " << my_arch_non_atomic_ulong << std::endl;
    }

    GitHub aguas arriba.

    Compilar y ejecutar:

    g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp -pthread
    ./main.out 2 10000

    Posible salida:

    my_non_atomic_ulong 15264
    my_arch_non_atomic_ulong 15267

    De esto podemos ver que el prefijo LOCK hizo la adición atómica: sin ella hemos condiciones de carrera en muchas de las agrega, y el recuento total que al final es menos de la sincronizado 20000.

    El prefijo de BLOQUEO se utiliza para implementar:

    Ver también: ¿Qué multinúcleo lenguaje ensamblador parece?

    Probado en Ubuntu 19.04 amd64.

    • ¿Cuál es el punto de usar -O0, de esgrima y de la no-atómica incremento con un total de barrera (lock inc)? Para demostrar que todavía roto, incluso en el mejor de los casos? Quieres ver muchos más perdido la cuenta si vamos a no bloqueado inc hacia delante de la tienda de búfer.
    • no había pensado mucho en él, de hecho por defecto para una mejor depuración, aunque yo laster notado que hace que sea un poco más fácil para ver el comportamiento que un simple caso porque -O3 optimiza el bucle para un único complemento. «y esgrima la no-atómica incremento con un total de barrera»: ¿de BLOQUEO también afectan a la no atómica variables en el programa anterior?
    • lock inc es una barrera, como mfence. Usted no tiene 4 lazos separados, que intercalar incrementos. No hacer que el otro inc atómica, pero las fuerzas de inc‘s tienda a ser mundialmente visible antes de la próxima inc‘s de la carga, así que sí afecta de forma significativa. Si usted no desea -O3 a la grúa fuera del bucle y hacer += N, puede utilizar volatile; de restricción de código-gen sin dar ningún tipo de atomicidad es lo que volatile es para.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea