4

最近の仕事で、マルチスレッド プログラムにカウンターを実装したいと考えています。私の GCC (3.4.5) には、atomic_tという名前のユーザー空間データ型があることがわかりました。しかし、それは本当のアトミックではないようです。

12コアのx86_64マシンでatomic_inc()/atomic_read()をテストしました.Linuxカーネルは2.6.9です。

これがデモです。pthread_cond_t と pthread_cond_broadcast を追加して、並行性の度合いを高めます。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include <asm/atomic.h>

atomic_t atomic_count;
pthread_cond_t g_cond;
pthread_mutex_t g_mutex;

void* thread_func(void*p) {
    pthread_mutex_t* lock = (pthread_mutex_t*)p;
    pthread_mutex_lock(lock);
    pthread_cond_wait(&g_cond, lock);
    pthread_mutex_unlock(lock);

    for (int i=0;i<20000;++i){
        atomic_inc(&atomic_count);
    }
    return NULL;
}
#define THRD_NUM 15

int main() {
    atomic_set(&atomic_count, 0);
    pthread_cond_init(&g_cond, NULL);
    pthread_mutex_init(&g_mutex, NULL);
    pthread_t pid[THRD_NUM];

    for (int i=0; i<THRD_NUM; i++) {
        pthread_create(&pid[i], NULL, thread_func, &g_mutex);
    }

    sleep(3);
    pthread_cond_broadcast(&g_cond);

    for (int i=0; i<THRD_NUM; i++) {
        pthread_join(pid[i], NULL);
    }

    long ans = atomic_read(&atomic_count);
    printf("atomic_count:%ld \n", ans);
}

期待される結果は 300000 ですが、代わりに常に 270000+ または 280000+ が得られます。私は、atomic_inc()の実装が

 static __inline__ void atomic_inc(atomic_t *v)
 {
     __asm__ __volatile__(
         LOCK "incl %0"
         :"=m" (v->counter)
         :"m" (v->counter));
 }

インテルのマニュアルによると、LOCKプレフィックスにはフル バリアの意味があります。それは、プログラムの出力が命令の並べ替えとは何の関係もないということですか?

さらに、興味深い現象を発見しました。THRD_NUMを 12 (マシンのコア番号) 未満に設定すると、エラーの頻度が低くなります。コンテキストスイッチが原因である可能性があると思います。しかし、これがどのように起こったのかわかりません。誰かが私を助けることができますか?ありがとう!

4

3 に答える 3

2

LOCK はマクロです。実際に何かを行うべきであるため、実際に「ロック」するように定義されていますか?

カーネル専用のヘッダーを使用していると確信しています。「asm」の下のものは、ユーザーランドで使用しないでください。

于 2013-07-25T15:10:44.847 に答える
0

<asm/atomic.h>Linuxカーネルヘッダーだと思いますか?それは確かに C の一部ではありません 。C11 には、通過するアトミックがあります<stdatomic.h>。ただし、新しい gcc に切り替える必要があります。

どこからマクロを取得しているのかわかりませんが、LOCK正しく定義されているとは思いません。Linux の asm/ atomic.hのバージョンでは、Google 検索LOCK_PREFIXで、 ではなくというマクロを使用していることがわかりますLOCK

以下は、atomic_inc のコードです。

93 static inline void atomic_inc(atomic_t *v)
94 {
95         asm volatile(LOCK_PREFIX "incl %0"
96                      : "+m" (v->counter));
97 }

これは次のようになります。

asm volatile("lock incl %0"
             : "+m" (v->counter));

マクロを気にするのをやめて、文字列を ( "lock incl %0") に入れるだけです。

次に、コンパイルして、単なるプレーン(なし)ではなく、命令が表示されることgcc -S myfile.cを確認しmyfile.sます。lock inclincllock

于 2013-07-25T17:00:05.497 に答える
-3

私は信じている

atomic_t atomic_count;

する必要があります

volatile atomic_t atomic_count;

それを試してみてください。

于 2013-07-25T14:55:39.607 に答える