2009-05-04 24 views
10

El siguiente código produce valores aleatorios para n y v. No es sorprendente que n sea aleatorio sin estar adecuadamente protegido. Pero se supone que v finalmente debería ser 0. ¿Hay algo mal en mi código? ¿O alguien podría explicar esto por mí? Gracias.Las operaciones de atomic.h parecen no ser atómicas

Estoy trabajando en un servidor de 4 núcleos de arquitectura x86. La unme es la siguiente.

Linux 2.6.9-22.ELsmp # 1 SMP Lun Sep 19 de 2005 18:00:54 EDT x86_64 x86_64 x86_64 GNU/Linux

#include <stdio.h> 
#include <pthread.h> 
#include <asm-x86_64/atomic.h> 

int n = 0; 
atomic_t v; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

#define LOOP 10000 

void* foo(void *p) 
{ 
    int i = 0; 
    for(i = 0; i < LOOP; i++) { 
//  pthread_mutex_lock(&mutex); 
     ++n; 
     --n; 
     atomic_inc(&v); 
     atomic_dec(&v); 
//  pthread_mutex_unlock(&mutex); 
    } 

    return NULL; 
} 

#define COUNT 50 

int main(int argc, char **argv) 
{ 
    int i; 
    pthread_t pids[COUNT]; 
    pthread_attr_t attr; 
    pthread_attr_init(&attr); 
    atomic_set(&v, 0); 

    for(i = 0; i < COUNT; i++) { 
     pthread_create(&pids[i], &attr, foo, NULL); 
    } 

    for(i = 0; i < COUNT; i++) { 
     pthread_join(pids[i], NULL); 
    } 

    printf("%d\n", n); 
    printf("%d\n", v); 
    return 0; 
} 
+5

No tengo una respuesta, pero me gustaría decir: gracias por hacer una pregunta clara, clara y sin ambigüedades con un código fuente completo. ¡Ojalá todos hicieran eso! – RichieHindle

Respuesta

3

¿Podemos echar un vistazo a la salida de ensamblador del código (gcc -E, creo). Incluso aunque la uname indica que es compatible con SMP, eso no necesariamente significa que se compiló con CONFIG_SMP.

Sin eso, la salida del código de ensamblador no tiene el prefijo lock y puede encontrar que sus núcleos interfieren entre sí.

Pero yo estaría utilizando las funciones pthread de todos modos, ya que son portátiles en más plataformas.

+4

Gracias. No encontré ningún prefijo de bloqueo en la salida gcc -E. Funcionará simplemente agregando #define CONFIG_SMP antes de incluir . Acutally este fragmento de código se usa para probar la eficacia de diferentes enfoques de incremento de seguridad de subprocesos. No es para producción :-) – Hank

4

This old post implica que

  • No es obvio que se supone que debe incluir este encabezado de núcleo en los programas de espacio de usuario
  • Se ha comprobado que no proporciona atomicidad para los programas de espacio de usuario.

Entonces ... ¿Quizás esa es la razón de los problemas que está viendo?

+0

Gracias por su información. Me pregunto por qué Linux kernel no expone estas primitivas útiles a los programas de usuario. Son más ligeros y eficientes que el enfoque pthread_mutex. – Hank

+0

@hank, bueno, el núcleo realmente lo hace. Su glibc que lo hace confuso. –

+0

@Hank: Bueno, porque no funcionan. Las operaciones atómicas requieren operaciones privilegiadas en algunas plataformas, que deben hacerse de forma muy diferente a kernel y userland. –

6

En su lugar, debe usar gcc built-ins (vea this) Esto funciona bien, y también funciona con icc.

int a; 
__sync_fetch_and_add(&a, 1); // atomic a++ 

Tenga en cuenta que debe tener en cuenta los problemas de consistencia de la memoria caché al modificar variables sin bloquear.

0

kernel de Linux atomic.h no se puede utilizar desde el sitio de usuario y nunca fue. En x86, algo de esto podría funcionar, porque x86 es una arquitectura bastante amigable con la sincronización, pero en algunas plataformas depende en gran medida de poder hacer operaciones privilegiadas (brazo más antiguo) o al menos de poder desactivar la apropiación (brazo y sparc más antiguos) al menos), que no es el caso en userland!

Cuestiones relacionadas