2010-03-01 10 views
7

Estoy buscando una forma de incrementar atómicamente un cortocircuito, y luego devolver ese valor. Necesito hacer esto tanto en modo kernel como en modo usuario, por lo que está en C, en Linux, en la arquitectura Intel de 32 bits. Desafortunadamente, debido a los requisitos de velocidad, un bloqueo mutex no será una buena opción.¿Cómo hacer un incremento atómico y buscar en C?

¿Hay alguna otra manera de hacerlo? En este punto, parece que la única opción disponible es alinear algún ensamblaje. Si ese es el caso, ¿podría alguien señalarme las instrucciones apropiadas?

Respuesta

7

GCC soporta operaciones atómicas:

gcc atomics

+0

En particular, '__sync_add_and_fetch' suena como lo que busca el OP. – caf

+0

Encontré esos antes, pero hay dos problemas. La primera es que entiendo que no funcionarán con el compilador kernel ... No estoy seguro de por qué es así, así que tal vez haya una solución fácil. En segundo lugar, incluso en el espacio de usuario, el enlazador me da el siguiente error: referencia indefinida a '__sync_add_and_fetch_2' Si alguien puede señalar soluciones a cualquiera de esos problemas (o ambos!) Yo estaría muy agradecido. – Bryan

+0

Al igual que una actualización, __sync_add_and_fetch funciona en el espacio de usuario, si incluye el distintivo -march = pentium al compilar (http://stackoverflow.com/questions/130740/link-error-when-compiling-gcc-atomic-operation- in-32-bit-mode), así que ahora estoy trabajando para que funcione en el módulo kernel. – Bryan

4

__atomic empotrados

A partir de GCC 4.8, __sync construidos-ins han sido desaprobados en favor de los __atomic muebles empotrados: https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html

Implementan el modelo de memoria C++, y std::atomic los usa internamente.

El siguiente ejemplo hilos POSIX falla constantemente con ++ en x86-64, y siempre trabaja con _atomic_fetch_add.

#include <assert.h> 
#include <pthread.h> 
#include <stdlib.h> 

enum CONSTANTS { 
    NUM_THREADS = 1000, 
    NUM_ITERS = 1000 
}; 

int global = 0; 

void* main_thread(void *arg) { 
    int i; 
    for (i = 0; i < NUM_ITERS; ++i) { 
     __atomic_fetch_add(&global, 1, __ATOMIC_SEQ_CST); 
     /* This fails consistently. */ 
     /*global++*/; 
    } 
    return NULL; 
} 

int main() { 
    int i; 
    pthread_t threads[NUM_THREADS]; 
    for (i = 0; i < NUM_THREADS; ++i) 
     pthread_create(&threads[i], NULL, main_thread, NULL); 
    for (i = 0; i < NUM_THREADS; ++i) 
     pthread_join(threads[i], NULL); 
    assert(global == NUM_THREADS * NUM_ITERS); 
    return EXIT_SUCCESS; 
} 

C11 _Atomic

En 5.1, el código anterior funciona con:

_Atomic int global = 0; 
global++; 

Pero creo threads.h aún no está implementado para crear realmente los hilos sin POSIX.

Cuestiones relacionadas