2

奇妙なエラーが発生します。次の2つの関数を実装しました。

int flag_and_sleep(volatile unsigned int *flag)
{
    int res = 0;

    (*flag) = 1;

    res = syscall(__NR_futex, flag, FUTEX_WAIT, 1, NULL, NULL, 0);
    if(0 == res && (0 != (*flag)))
        die("0 == res && (0 != (*flag))");
    return 0;
}

int wake_up_if_any(volatile unsigned int *flag)
{
    if(1 == (*flag))
    {
        (*flag) = 0;
        return syscall(__NR_futex, flag, FUTEX_WAKE, 1, NULL, NULL, 0);
    }
    return 0;
}

そして、2つのPosixスレッドを実行してそれらをテストします。

static void die(const char *msg)
{
    fprintf(stderr, "%s %u %lu %lu\n", msg, thread1_waits, thread1_count, thread2_count);
    _exit( 1 );
}

volatile unsigned int thread1_waits = 0;

void* threadf1(void *p)
{
    int res = 0;
    while( 1 )
    {
        res = flag_and_sleep( &thread1_waits );
        thread1_count++;
    }
    return NULL;
}

void* threadf2(void *p)
{
    int res = 0;
    while( 1 )
    {
        res = wake_up_if_any( &thread1_waits );
        thread2_count++;
    }

    return NULL;
}

thread2が100万回ほど繰り返された後、私はassertfireを受け取ります。

./a.out 0 == res &&(0!=(* flag))1 261129 1094433

これは、syscall(したがってdo_futex())が0を返したことを意味します。男性は、do_futex(WAKE)呼び出しによってウェイクアップされた場合にのみそうする必要があると言います。しかし、WAKE呼び出しを行う前に、フラグを0に設定しました。ここでは、フラグはまだ1であるように見えます。

これはIntelです。これは強力なメモリモデルを意味します。したがって、thread1でthread2のシステムコールの結果が表示された場合、呼び出し前のスレッド2での書き込みの結果も表示する必要があります。

フラグとそれへのすべてのポインターは揮発性であるため、gccが正しい値の読み取りに失敗する可能性があるかどうかはわかりません。

私は困惑しています。

ありがとう!

4

1 に答える 1

2

レースは、スレッド1がフルサイクルになると発生し、スレッド2が

(*flag) = 0;

return syscall(__NR_futex, flag, FUTEX_WAKE, 1, NULL, NULL, 0);

したがって、テストは失敗しています。

于 2010-12-03T15:53:14.003 に答える