Domanda

C'è un (POSIX-) modo portabile in C per operazioni di variabili atomiche simile ad una filettatura portatile con pthread?

Le operazioni atomiche sono operazioni come "incremento e ottenere" che vengono eseguiti atomicamente che significa che nessun cambio di contesto può interferire con il funzionamento. Nello spazio del kernel di Linux, dobbiamo atomic_t tipo, in Java abbiamo la java.util.concurrent.atomic pacchetto .

In Linux, il file atomic.h fornisce operazioni atomiche, ma l'inclusione è la piattaforma per esempio dipendente #include <asm-x86_64/atomic.h> e non è disponibile su Mac OS X in modo simile.

È stato utile?

Soluzione

A partire dal C11 c'è un atomica libreria che fornisce operazioni atomiche. Questo è portabile su qualsiasi piattaforma che ha un compilatore C11 (come gcc-4.9) con questa funzione opzionale.

La presenza del atomica può essere controllato con __STDC_NO_ATOMICS__and la presenza di <stdatomic.h>

atomic.c

#include <stdio.h>
#include <stdlib.h>
#ifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#endif

int main(int argc, char**argv) {
    _Atomic int a;
    atomic_init(&a, 42);
    atomic_store(&a, 5);
    int b = atomic_load(&a);
    printf("b = %i\n", b);

    return EXIT_SUCCESS;
}

invocazioni compilatore

clang -std=c11 atomic.c
gcc -std=c11 atomic.c

Altri suggerimenti

Per chi si imbatte in questo in futuro, Atomics C11 sono il modo migliore per farlo ora - io credo che saranno inclusi nel GCC 4.9

.

Dal momento che hai chiesto per OS X:

(e poiché platformity croce è stata sollevata in questo thread.)

OS X dispone di funzioni OSAtomicAdd32 () e amici. Essi sono dichiarati in "/usr/include/libkern/OSAtomic.h". Vedere La Threading guida di programmazione , "Uso Operazioni atomiche".

E per Windows, v'è InterlockedIncrement () e amici (vedi MSDN).

Insieme ai comandi incorporati gcc __ sync_fetch_and_add () e amici (è stato collegato in precedenza), si dovrebbe avere qualcosa per ogni piattaforma desktop principale.

Si prega di notare che non ho ancora li uso da solo, ma forse lo farà nei prossimi giorni.

No, POSIX non specifica qualsiasi portatili / operazioni atomiche senza blocchi. Ecco perché hanno pthread.

Si sta sia andando ad avere per utilizzare metodi non standard o bastone con ptrheads per la portabilità.

Atomics C11 minimo esempio eseguibile

Con l'aggiunta di thread nel glibc 2.28, siamo in grado di fare entrambe le Atomics e filettatura in puro C11.

Esempio da: https://en.cppreference.com/w/c/ lingua / atomica

main.c

#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>

atomic_int acnt;
int cnt;

int f(void* thr_data)
{
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
        // for this example, relaxed memory order is sufficient, e.g.
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}

int main(void)
{
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);

    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Compilare ed eseguire:

gcc -std=c11 main.c -pthread
./a.out

uscita possibile:

The atomic counter is 10000
The non-atomic counter is 8644

Il contatore non-atomico è molto probabile che sia più piccola di quella atomica causa di accesso filante attraverso fili alla variabile non atomico.

A pthreads esempio può essere trovato all'indirizzo: Come posso iniziare le discussioni in pianura C?

Testato in Ubuntu 18.04 (glibc 2.27) mediante la compilazione di glibc dalla fonte: più librerie glibc su un singolo host Ubuntu 18.10 ha glibc 2.28 così le cose dovrebbero solo lavorare lì.

Per quanto ne sappia non ci sono modi cross-platform per fare operazioni atomiche. Ci può essere una biblioteca là fuori, ma non so di. La sua non è particolarmente difficile da rotolare il proprio, però.

Non credo che ci sia.

Un modo per risolverlo, licenze permettendo ovviamente, sarebbe quello di copiare le relative implementazioni per-architettura per esempio lo spazio del kernel di Linux. Non ho seguito l'evoluzione di quei primitivi da vicino, ma direi che sono effettivamente primitive, ossia non dipendono altri servizi o API nel kernel.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top