Pergunta

Eu tenho um cenário simples de produtor/consumidor, onde há apenas um único item sendo produzido/consumido. Além disso, o produtor espera que o tópico do trabalhador termine antes de continuar. Percebo que isso evita todo o ponto de leitura multithread, mas assuma que realmente precisa ser assim (:

Este código não é compilado, mas espero que você tenha a ideia:

// m_data is initially null

// This could be called by any number of producer threads simultaneously
void SetData(object foo)
{
    lock(x)                      // Line A
    {
        assert(m_data == null);
        m_data = foo;
        Monitor.Pulse(x)         // Line B
        while(m_data != null)
            Monitor.Wait(x)      // Line C
    }
}

// This is only ever called by a single worker thread
void UseData()
{
    lock(x)                      // Line D
    {
        while(m_data == null)
            Monitor.Wait(x)      // Line E
        // here, do something with m_data
        m_data = null;
        Monitor.Pulse(x)         // Line F
    }
}

Aqui está a situação que eu não tenho certeza:

Suponha que muitos threads chamem o setData () com entradas diferentes. Apenas um deles entrará na fechadura e o restante será bloqueado na linha A. Suponha que o que entrou nos conjuntos de bloqueio m_data e faz o seu caminho para a linha C.

Pergunta: A espera () na linha C permitir que outro fio na linha A obtenha a trava e substitua m_data Antes que o tópico do trabalhador chegue a ele?

Supondo que isso não aconteça, e o fio do trabalhador processa o original m_data, e, eventualmente, vá para a linha F, o que acontece quando esse pulso () dispara?

Somente o thread aguardando na linha C poderá obter a fechadura? Ou estará competindo com todos os outros threads esperando na linha A também?

Essencialmente, quero saber se Pulse ()/Wait () se comunica especialmente "sob o capô" ou se eles estão no mesmo nível com Lock ().

A solução para esses problemas, se houver, é óbvia, é claro - apenas Surround setData () com outra trava - digamos, bloqueio (y). Estou curioso para saber se é um problema para começar.

Foi útil?

Solução

Não há garantia de que o consumidor seja inserido na fila de espera ou pronta diante de outro produtor.
Os monitores de estilo C# e Java são descritos em Wikipedia, em "Monitores de Condição implícita".
Uma boa visão geral do que acontece em Monitor (Tirado de isto excelente site):alt text

"A espera () na linha C permitir que outro fio na linha A obtenha a fechadura e substitua M_Data antes mesmo de o tópico do trabalhador chegar?"

Suponha que SetData() é chamado por dois threads de produtores, P1 & P2.
Um tópico de consumo, C1 é iniciado também.
P1, P2 e C1 todos entram na fila pronta.
P1 adquire a fechadura primeiro.
A fila de espera está vazia, Pulse() sobre line B não tem efeito.
P1 espera line C, então é colocado na fila de espera.
O próximo thread na fila Ready adquire a fechadura.
Pode ser igualmente P2 ou C1 - No primeiro caso, a afirmação falha.
Você tem uma condição de corrida.

"Supondo que isso não aconteça, e o fio do trabalhador processa o M_Data original e, eventualmente, segue para a linha F, o que acontece quando esse pulso () dispara?"

Ele moverá um garçom da fila de espera para a fila pronta.
A fechadura é mantida pelo tópico que emite o Pulse().
O fio notificado vai ter uma chance Para adquirir a fechadura após o lixo pulsante, a trava (já pode haver outros na fila pronta).
A partir de Msdn, monitor.pulse ():
"O segmento que atualmente possui a trava no objeto especificado chama esse método para sinalizar o próximo fio na fila para a trava. Ao receber o pulso, o fio de espera é movido para a fila pronta. Quando o fio que invocou o pulso libera a fechadura da fechadura , o próximo tópico na fila pronta (que não é necessariamente o segmento que foi pulsado) adquire a trava ".

"Somente o fio aguardando na linha C poderá conseguir a fechadura? Ou estará competindo com todos os outros threads esperando na linha A também?"

Todos os threads que estão na fila pronta "competem" por ter a trava a seguir.
Não importa se eles chegaram lá direto ou da fila de espera por meio de Pulse().

As "filas" podem ser implementadas por outros meios. (Não o fila estrutura de dados como tal).
Assim a Monitor A implementação pode não garantir justiça - mas pode ter maior taxa de transferência/desempenho geral.

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