我收到一个奇怪的错误。我实现了以下两个功能:

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;
}

并通过运行两个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进行了大约一百万次迭代后,我得到了断言:



这意味着系统调用-从而do_futex()-返回0。Man说只有在被do_futex(WAKE)调用唤醒后才这样做。但是然后在我进行WAKE调用之前,我将标志设置为0。这里看起来标志仍然是1。

这就是Intel,这意味着强大的内存模型。因此,如果在线程1中看到线程2中系统调用的结果,我还必须看到在调用之前在线程2中写入的结果。

标志和指向它的所有指针都是 Volatile 的,所以我看不到gcc如何无法读取正确的值。

我很困惑。

谢谢!

最佳答案

线程1进入完整周期时发生竞争,而线程2退出时重新进入等待调用

(*flag) = 0;


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

因此测试是错误的。

10-04 12:42