Pergunta

Estou fazendo IPC em Linux usando boost::interprocess::shared_memory_object como por de referência (anônimo exemplo mutex).

Há um processo servidor, que cria a shared_memory_object e escreve para ele, enquanto segurava um interprocess_mutex envolto em um scoped_lock; e um processo cliente que imprime tudo o que o outro tem escrito -. Neste caso, é uma int

Eu corri para um problema:. Se o servidor dorme enquanto segura a exclusão mútua, o processo cliente nunca é capaz de adquirir-lo e espera para sempre

Buggy Servidor loop:

using namespace boost::interprocess;
int n = 0;
while (1) {
    std::cerr << "acquiring mutex... ";
    {
        // "data" is a struct on the shared mem. and contains a mutex and an int
        scoped_lock<interprocess_mutex> lock(data->mutex);
        data->a = n++;
        std::cerr << n << std::endl;
        sleep(1);
    } // if this bracket is placed before "sleep", everything works
}

Servidor de saída:

acquiring mutex... 1
acquiring mutex... 2
acquiring mutex... 3
acquiring mutex... 4

Cliente loop:

while(1) {
   std::cerr << "acquiring mutex... ";
   {
      scoped_lock<interprocess_mutex> lock(data->mutex);
      std::cerr << data->a << std::endl;
   }
   sleep(1);
}

Cliente de saída (espera para sempre):

acquiring mutex...

A coisa é, se eu mover o suporte para a linha antes da chamada sleep, tudo funciona. Por quê? Eu não acho que dormir com um mutex bloqueado causaria o mutex a ser eternamente trancado.

A única teoria que tenho é que quando o kernel acorda o processo do servidor, as extremidades de escopo e o mutex é liberado, mas o processo de espera não é dada a oportunidade de executar. O servidor, em seguida, re-adquire o bloqueio ... Mas isso não parece fazer muito sentido.

Obrigado!

Foi útil?

Solução

A sua teoria está correta.

Se você olhar para a parte inferior do exemplo mutex anônimo na referência é ligada, você verá

Como podemos ver, a exclusão mútua é útil para dados proteger, mas não notificar a outro processo de um evento.

Ao soltar o mutex não notifica qualquer outra pessoa que poderia estar esperando nele, e desde que o seu processo acabou de acordar, ele quase certamente tem abundância de seu quantum de agendamento para a esquerda para fazer mais trabalho. Ele fará um loop em volta e re-adquirir o mutex antes de ele dorme novamente, o que é a primeira oportunidade que o cliente tem de adquirir o mutex em si.

Mover o exterior sleep() servidor dos meios de escopo que vai dormir enquanto o mutex é livre, dando ao cliente a oportunidade de correr e adquirir o mutex por si.

Tente chamar sched_yield() (Linux apenas) se você quiser desistir do processador, mas ainda sono dentro de seu escopo. sleep(0) também pode funcionar.

Outras dicas

dormir, mantendo um mutex é errado. Mutex protege alguns dados (ou seja, data-> a) e alcance devem ser minimizados em torno de leitura / gravação de dados.

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