Операции с atom.h кажутся неатомными

Следующий код создает случайные значения как для n, так и для v. Неудивительно, что n является случайным, не защищенным должным образом. Но предполагается, что v должно, наконец, быть 0. Есть ли что-то не так в моем коде? Или кто-нибудь может объяснить это мне? Спасибо.

Я работаю над 4-ядерным сервером архитектуры x86. Uname выглядит следующим образом.

Linux 2.6.9-22.ELsmp # 1 SMP Mon Sep 19 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;
}

Ответ 1

Можем ли мы посмотреть на вывод ассемблера кода (gcc -E, я думаю). Даже подумал, что uname указывает на SMP-осведомленность, что не обязательно означает, что он был скомпилирован с помощью CONFIG_SMP.

Без этого выход кода ассемблера не имеет префикса lock, и вы можете обнаружить, что ваши ядра мешают друг другу.

Но я все равно буду использовать функции pthread, поскольку они переносятся на другие платформы.

Ответ 2

Вместо этого вы должны использовать встроенные gcc (см. this). Это прекрасно работает, а также работает с icc.

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

Обратите внимание, что при изменении переменных без блокировки вы должны знать о проблемах с целостностью кеша.

Ответ 3

Это старое сообщение подразумевает, что

  • Не очевидно, что вы должны включить этот заголовок ядра в программы пользовательского пространства.
  • Известно, что он не обеспечивает атомарность для программ пользовательского пространства.

Итак... Возможно, это причина проблем, которые вы видите?

Ответ 4

Ядро Linux atomic.h не может использоваться из userland и никогда не было. На x86 некоторые из них могут работать, потому что x86 - это довольно дружественная к синхронизации архитектура, но на некоторых платформах она в значительной степени зависит от возможности выполнять привилегированные операции (более старшая рука) или, по крайней мере, от возможности отключить преемственность (более старые руки и спарки по крайней мере), чего нет в userland!