2009-05-04 14 views
10

Il seguente codice produce valori casuali per entrambi n e v. Non sorprende che n sia casuale senza essere adeguatamente protetto. Ma si suppone che v dovrebbe finalmente essere 0. C'è qualcosa di sbagliato nel mio codice? O qualcuno potrebbe spiegarlo per me? Grazie.Le operazioni da atomic.h sembrano non atomiche

Sto lavorando su un server 4-core di architettura x86. L'uname è il seguente.

Linux 2.6.9-22.ELsmp # 1 SMP Lun 19 Set 18:00:54 EDT 2005 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

Non ho una risposta, ma mi piacerebbe dire: grazie per aver chiesto una domanda chiaramente formulata, senza ambiguità con codice sorgente funzionante completo. Vorrei che tutti lo facessero! – RichieHindle

risposta

3

Possiamo dare un'occhiata all'output dell'assembler del codice (gcc -E, credo). Anche se l'uname indica che è SMP-aware, questo non significa necessariamente che sia stato compilato con CONFIG_SMP.

In caso contrario, l'output del codice assembler non ha il prefisso lock e si possono rilevare interferenze tra i core.

Ma io utilizzerei comunque le funzioni pthread poiché sono portatili su più piattaforme.

+4

Grazie. Non ho trovato alcun prefisso di blocco nell'output di gcc -E. Funzionerà semplicemente aggiungendo #define CONFIG_SMP prima di includere . Acutally questo pezzo di codice viene utilizzato per testare l'efficienza di diversi approcci di incremento sicuri del thread. Non è per la produzione. :-) – Hank

4

This old post implica che

  • Non è ovvio che dovresti includere questa intestazione del kernel nei programmi userspace
  • È noto che non è in grado di fornire l'atomicità per i programmi userspace.

Quindi ... Forse questa è la ragione dei problemi che stai vedendo?

+0

Grazie per l'informazione. Mi chiedo solo perché il kernel di Linux non espone questi primitivi utili ai programmi di userland. Sono più leggeri ed efficienti rispetto all'approccio pthread_mutex. – Hank

+0

@hank, beh, il kernel effettivamente lo fa. Il suo glibc che lo rende confuso. –

+0

@Hank: Beh, perché non funzionano. Le operazioni atomiche richiedono operazioni privilegiate su alcune piattaforme, che devono essere fatte in modo molto diverso dal kernel e dall'uso. –

6

È consigliabile utilizzare gcc built-in (vedere this) Funziona bene e funziona anche con icc.

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

Si noti che è necessario conoscere i problemi di coerenza della cache quando si modificano le variabili senza il blocco.

0

Il kernel Linux atomic.h non è utilizzabile da parte dell'utente e non lo è mai stato. Su x86, alcuni di essi potrebbero funzionare, perché x86 è piuttosto un'architettura compatibile con la sincronizzazione, ma su alcune piattaforme si basa pesantemente sulla possibilità di eseguire operazioni privilegiate (braccio più vecchio) o almeno sulla possibilità di disabilitare la prelazione (braccio precedente e sparc almeno), che non è il caso in terra utente!

Problemi correlati