Problema con codice produttore / consumatore multiplo e sezione critica
-
05-07-2019 - |
Domanda
Sto tentando un problema produttore / consumatore multiplo in C, ma non funziona come previsto. Di seguito è riportato uno pseudo codice per rappresentare la mia implementazione.
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);
}
Tuttavia, con questa soluzione i dati 1 si riempiranno, ma thread2 si bloccherà e non verrà mai eseguito. C'è qualcosa di sbagliato nella mia implementazione?
EDIT # 1
Uno dei problemi che ho riscontrato è stato che il mio secondo mutex non veniva creato correttamente. Non so cosa ci sia di sbagliato, quindi sto solo usando il primo mutex per tutti i thread. C'è anche qualcos'altro che ho fatto per farlo funzionare, quindi aggiornerò il mio pseudo-codice per riflettere questo in seguito quando avrò un minuto.
Soluzione
Assicurati di pubblicare data1_empty
e data2_empty
inizialmente.
Altri suggerimenti
Se usi una sorta di tipo di accodamento per Dati
, dovresti essere in grado di rimuovere il " vuoto " semafori completamente, a meno che tu non stia cercando di imporre la condizione che ogni profondità della coda Data
sia rigorosamente 0 o 1. Se usi una variabile locale in thread2
, puoi ridurre la dimensione della sezione critica.
Il codice diventa quindi qualcosa del genere:
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
}
Cosa ha detto wrang-wrang e cerca di non tenere il blocco per data_1 mentre aspetti data_2_empty. È possibile ottenere ciò mantenendo un buffer alternativo per data_1 e data_2 che si scambiano. Thread_2 scambia dati_1 durante l'elaborazione in data_2, thread_3 scambia dati_2 durante l'elaborazione. Il tuo pseudo-codice corrente consentirà l'esecuzione simultanea del thread 1 e del thread 3, ma non consentirà l'esecuzione del thread 2 contemporaneamente a uno degli altri.