代码之家  ›  专栏  ›  技术社区  ›  n-alexander

使用Do Futex时搞砸了?

  •  2
  • n-alexander  · 技术社区  · 16 年前

    我有个奇怪的错误。我实现了这两个功能:

    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进行了大约一百万次迭代之后,我得到了assert fire:

    /A.OUT 0==res&&(0!=(*标志))1 261129 1094433

    这意味着syscall——因此也会返回0。男人说只有在被叫醒的时候才会这样做。但在我执行叫醒之前,我将标志设置为0。这里的标志仍然是1。

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

    标志和指向它的所有指针都是不稳定的,所以我不知道GCC如何无法读取正确的值。

    我困惑不解。

    谢谢!

    1 回复  |  直到 15 年前
        1
  •  2
  •   n-alexander    15 年前

    当线程1进入完整的循环,当线程2从

    (*flag) = 0;
    

    到

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

    所以测试是错误的。

    推荐文章
    Bob  ·  boost-timed_wait不等待
    11 年前