es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Copie atómicamente un bit (o bits) en un entero

Tengo un código que copia bits enmascarados en un entero, primero limpiándolos en el entero de destino y luego combinándolos mediante la operación OR.

Así:

bitsToSet = 6
targetInt &= ~(1 << bitsToSet)
targetInt |= desiredBitValue << bitsToSet

El problema es que ahora necesita ser seguro para hilos, y necesito que la operación sea atómica. Creo que usar std:atomic solo haría cada suboperación atómica pero no la operación en su conjunto.

¿Cómo puedo hacer que toda la operación (incluyendo tanto las operaciones &= como las |=) sea atómica?

Por ejemplo, resolvería el problema para mí si tuviera una función (o mejor, una macro) como SetBits(TARGET, MASK, VALUE) que configurara atómicamente los bits enmascarados en TARGET con el valor VALUE. La MÁSCARA y el VALOR ya pueden estar desplazados a la izquierda.

Mi código actual no atómico es:
\#define SetBits(TARGET, MASK, VALUE) {(TARGET) &= ~((uint64_t)MASK); (TARGET)|=((uint64_t)VALUE);}

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para hacer que toda la operación sea atómica, puedes usar la operación compare-and-swap (CAS) proporcionada por la biblioteca std::atomic. La operación CAS te permite actualizar de forma atómica un valor solo si no ha cambiado desde la última lectura. Aquí hay un ejemplo de implementación de la función SetBits utilizando CAS:

    #define SetBits(TARGET, MASK, VALUE) \
        do \
        { \
            uint64_t oldValue = TARGET.load(); \
            uint64_t newValue = (oldValue & ~MASK) | VALUE; \
        } while (!TARGET.compare_exchange_weak(oldValue, newValue));
    

    En esta implementación, primero cargamos el valor actual del entero objetivo en una variable local llamada oldValue. Luego calculamos el nuevo valor haciendo un AND entre el valor antiguo y el inverso de la máscara, y luego haciendo un OR entre el resultado y el valor deseado. Finalmente, utilizamos la operación CAS para actualizar el entero objetivo con el nuevo valor, pero solo si el valor antiguo no ha cambiado desde la última lectura. Si la operación CAS falla (es decir, si el valor antiguo ha cambiado), repetimos el proceso hasta que logremos actualizar el entero objetivo de forma atómica.

Comments are closed.