Pregunta


Estoy usando la operación atómica proporcionada por Sunos enu003Csys/atomic.h> , cual es
void *atomic_cas_ptr(volatile void *target, void *cmp, void *newval);

Ahora para hacer es utilizable, tengo que verificar si el valor antiguo devuelto por esta función y aprobado por la función de Callee CMP es el mismo, si la operación es exitosa.
Pero tengo ciertas dudas: a medida que esta función devuelve un puntero vacío al valor anterior, llamemos nulo *viejo y estoy pasando void *cmp, entonces necesito comparar estos dos viejos y CMP, así que cómo voy a comparar estos dos ? Y si mientras se comparaba *Old se cambió, ¿qué voy a hacer?
En esencia, lo que quiero hacer es deformar esta función, dentro de otra función que toma estos tres argumentos y devuelve verdadero o falso, lo que indica el éxito o el fracaso.
acerca de CAS, leí que es un nombre inapropiado llamarlo operación libre de bloqueos, ya que finalmente toma el bloqueo en el hardware (bloqueo en el bus), ¿es correcto? Es por eso que el CAS es una operación costosa.

¿Fue útil?

Solución

Posiblemente la declaración de función te confundió. Esta función no devuelve un puntero al valor antiguo (¿de qué?), Pero el valor anterior de la memoria apunta por target (que realmente debería ser un puntero a la nula*, es decir void* volatile * target).

Por lo general, si una primitiva CAS devuelve un valor antiguo en lugar de un bool, verifica el éxito de CAS con algo como esto:

void* atomic_ptr; // global atomically modified pointer

void* oldval, newval, comparand; // local variables
/* ... */
oldval = atomic_cas_ptr( (void*)&atomic_ptr, /* note that address is taken */
                          comparand, newval );
if( oldval == comparand ) {
    // success
} else {
    // failure
}

Entonces, cuando compara Old_Val y Comparand, trabaja con variables locales que no cambian simultáneamente (mientras que Global Atomic_PTR podría cambiarse nuevamente), y compara los valores de puntero sin desferenciar.

La función que desea debe ser así:

bool my_atomic_cas_ptr(volatile void* target, void* comparand, void* newval)
{
    return (comparand == atomic_cas_ptr(target, comparand, newval));
}

Tenga en cuenta que, dado que en algunos algoritmos el valor anterior (el anterior a CAS) debe ser conocido, es mejor que un CAS primitivo devuelva el valor anterior en lugar de un bool, ya que puede construir fácilmente el segundo mientras lo contrario es más complejo e ineficiente (consulte el siguiente código que intenta obtener el valor antiguo correcto de un macOS Cas primitivo que devuelve un bool).

void* CAS(void* volatile* target, void* comparand, void* newval)
{
    while( !OSAtomicCompareAndSwapPtr(comparand, newval, target) ) {
        void* snapshot = *target;
        if( snapshot!=comparand ) return snapshot;
    }
    return comparand;
}

En cuanto al bus de memoria de bloqueo de CAS, depende del hardware. Era cierto para los antiguos procesadores X86, pero en los sistemas modernos X86 es diferente. Primero, no hay autobús central; Fue reemplazado por HyperTransport de AMD y la interconexión QuickPath de Intel. En segundo lugar, en las recientes generaciones de CPU, las instrucciones bloqueadas no están todas serializadas (ver algunos datos mostrando que las instrucciones bloqueadas en diferentes direcciones de memoria no interfieren). Y finalmente, en la definición comúnmente aceptada La libertad de bloqueo es la garantía del progreso en todo el sistema, no la ausencia de sincronización de serialización.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top