испортил использование do_futex? - PullRequest
2 голосов
/ 31 августа 2010

Я получаю странную ошибку.Я реализовал эти две функции:

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 было около миллиона итераций, я получил огонь подтверждения:

. / A.out 0 == res && (0! = (* Flag)) 1 261129 1094433

Это означает, что системный вызов - и, следовательно, do_futex() - вернул 0. Человек говорит, что должен делать это только в том случае, если его разбудит вызов do_futex (WAKE).Но затем, прежде чем я сделаю вызов WAKE, я установлю флаг на 0. Здесь кажется, что флаг все еще равен 1.

Это Intel, что означает сильную модель памяти.Поэтому, если в потоке 1 я вижу результаты системного вызова в потоке 2, я также должен увидеть результаты записи в потоке 2, которая была до вызова.

Флаг и все указатели на него являются изменчивыми, поэтому я неЯ не вижу, как gcc может не прочитать правильное значение.

Я сбит с толку.

Спасибо!

1 Ответ

2 голосов
/ 03 декабря 2010

гонка происходит, когда поток 1 проходит полный цикл и повторно вводит вызов WAIT, когда поток 2 переходит с

(*flag) = 0;

на

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

Таким образом, тест является ошибочным.1007 *

...