Pergunta

Estou recebendo um erro estranho. Eu implementei essas duas funções:

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

e teste -os executando dois threads 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;
}

Depois que o Thread2 teve um milhão de iterações, eu recebo o fogo afirmado:

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

Isso significa que o syscall - e, assim, do_futex () - retornou 0. O homem diz que só deve fazê -lo se acordado por uma chamada do_futex (despertar). Mas então, antes de fazer uma chamada de despertar, eu defino o sinalizador para 0. Aqui parece que o sinalizador ainda é 1.

Isso é Intel, o que significa um modelo de memória forte. Portanto, se no Thread1 vejo os resultados de um syscall no Thread2, também devo ver os resultados da gravação no Thread 2, que foi antes da chamada.

A bandeira e todos os ponteiros são voláteis, então não vejo como o GCC pode deixar de ler o valor correto.

Estou confuso.

Obrigado!

Foi útil?

Solução

A corrida acontece quando o thread 1 passa o ciclo completo e as reentradoras esperam a chamada quando o thread 2 vai de

(*flag) = 0;

para

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

Portanto, o teste está com defeito.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top