Multiple produtor / consumidor e problema de código seção crítica
-
05-07-2019 - |
Pergunta
Eu estou tentando um problema múltiplo produtor / consumidor em C, mas não o seu trabalho como esperado. O seguinte é algum código pseudo para representar minha implementação.
Thread thread1;
Thread thread2;
Thread thread3;
Data data1;
Mutex data1_mutex;
Semaphore data1_empty;
Semaphore data1_fill;
Data data2;
Mutex data2_mutex;
Semaphore data2_empty;
Semaphore data2_fill;
thread1()
{
// creates data and places it into data1.
wait(data1_empty);
lock(data1_mutex);
// critical section
unlock(data1_mutex);
post(data1_fill);
}
thread2()
{
// Removes data from data1, processes it, and places it into data2.
// data1
wait(data1_fill);
lock(data1_mutex);
// data2
wait(data2_empty);
lock(data2_mutex);
// critical section
// data2
unlock(data2_mutex);
post(data2_fill);
// data1
unlock(data1_mutex);
post(data1_empty);
}
thread3()
{
// Removes data from data2, prints its results, and removes it.
wait(data2_fill);
lock(data2_mutex);
// critical section
unlock(data2_mutex);
post(data2_empty);
}
No entanto, com esta solução data1 vai encher-se, mas thread2 irá travar e nunca executado. Há algo de errado com a minha implementação?
EDIT # 1
Um dos problemas que eu encontrei foi que a minha segunda mutex não estava sendo criado corretamente. Eu não sei o que está errado com ele assim que eu estou usando apenas o primeiro de exclusão mútua para todos os tópicos. Há também uma outra coisa que eu fiz para fazê-lo funcionar, então eu vou atualizar meu pseudo-código para refletir isso mais tarde quando eu tenho um minuto.
Solução
Certifique-se de pós data1_empty
e data2_empty
inicialmente.
Outras dicas
Se você usar algum tipo de fila tipo para Data
, você deve ser capaz de remover os semáforos "vazios" completamente, a menos que você está tentando impor a condição de que cada profundidade da fila Data
é estritamente 0 ou 1. Se você usar uma variável local em thread2
, você pode reduzir o tamanho da seção crítica.
O código torna-se então algo como isto:
thread1() {
//Wait for data to put in the queue (i.e. a blocking socket read)
lock(data1_mutex);
data1.push(someData);
unlock(data1_mutex);
post(data1_fill);
}
thread2() {
DataType dataElement;
wait(data1_fill);
lock(data1_mutex);
dataElement = data1.pop();
unlock(data1_mutex);
lock(data2_mutex);
data2.push(dataElement);
unlock(data2_mutex);
post(data2_fill);
}
thread3() {
DataType dataElement;
wait(data2_fill);
lock(data2_mutex);
dataElement = data2.pop();
unlock(data2_mutex);
//do something with dataElement here
}
O que wrang-wrang disse, e não tentar manter o bloqueio para dados_1 enquanto você está esperando para data_2_empty. Você poderia conseguir isso, mantendo um tampão alternativo para dados_1 e dados_2 que você trocar. Thread_2 swaps dados_1 ao processar-lo em dados_2, thread_3 swaps fora dados_2 enquanto processá-lo. Seu pseudo-código atual permitirá linha 1 e linha 3 para executar simultaneamente, mas não permitirá fio 2 para executar ao mesmo tempo que qualquer um dos outros.