испортил использование do_futex?
-
26-09-2019 - |
Вопрос
Я получаю странную ошибку. Я реализовал эти две функции:
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! = (* флаг)) 1 261129 1094433
Это означает, что syscall - и тем самым do_futex () - вернул 0. Человек говорит, что он должен сделать это, если проснулся только по вызову do_futex (Wake). Но потом до того, как я сделаю звонок после звонка, я установил флаг до 0. Здесь появляется, что флаг по-прежнему 1.
Это Intel, что означает сильную модель памяти. Итак, если в Thread1 я вижу результаты из Syscall в Thread2, я также должен увидеть результаты записи в потоке 2, который был до вызова.
Флаг и все указатели на это летучие, поэтому я не вижу, как GCC может не прочитать правильное значение.
Я сбился с толку.
Спасибо!
Решение
Гонка происходит, когда нить 1 идет полный цикл, и повторно входит в позвоните, когда нить 2 идет от
(*flag) = 0;
к
return syscall(__NR_futex, flag, FUTEX_WAKE, 1, NULL, NULL, 0);
Таким образом, тест неисправен.