2016-01-31 15 views
9

Pisałem program, który uruchamia dwa procesy.Dwa typy wiadomości w kolejce wiadomości

Pierwszy proces, "klient" wysyła dwa rodzaje wiadomości.

Pierwszy typ zwiększa współużytkowany zasób (int). Drugi typ ustawia zasób na 0.

Po 10 wiadomościach klient musi wysłać wiadomość o specjalnym typie, która spowoduje zatrzymanie wątków nasłuchujących w dwóch kolejkach. Tak więc klient wysyła dwie wiadomości (jedną dla każdej kolejki) ze specjalną wartością w polu typu, aby zakończyć wątki.

Drugi proces to "serwer".

Serwer posiada trzy wątki:

pierwszy nasłuchuje w kolejce „wzrost”. Musi obsłużyć żądanie zwiększenia do czasu komunikatu o zakończeniu. Więc napisałem:

do{ 
msgrcv(id_i,&msg,dimensione,INCREMENTA,0); 
pthread_mutex_lock(&mutex); 
printf("THREAD 1: Il contatore vale:%d\n",*contatore); 
incremento = msg.contenuto; 
printf("THREAD 1: Incremento di : %d\n",incremento); 
    *contatore+=incremento; 
printf("THREAD 1: Il contatore vale:%d\n",*contatore); 
pthread_mutex_unlock(&mutex); 
msgrcv(id_i,&msg,dimensione,TERMINA,IPC_NOWAIT); //IPC_NOWAIT or the thread will 
freeze after the first message 
} 
while(msg.tipo!=TERMINA); 

Drugi musi obsłużyć „ustawiony na” 0 żądań aż pojawi się komunikat o zakończeniu.

do{msgrcv(id_a,&msg,dimensione,AZZERA,0); 
pthread_mutex_lock(&mutex); 
printf("THREAD 2: IL CONTATORE VALE:%d\n",*contatore); 
*contatore=0; 
printf("Thread 2: Contatore azzerato. Ora vale : %d\n",*contatore); 
pthread_mutex_unlock(&mutex); 
msgrcv(id_a,&msg,dimensione,TERMINA,IPC_NOWAIT);//IPC_NOWAIT or the thread will 
freeze after the first message 
} 
while(msg.tipo!=TERMINA); 

Trzeci wątek zwiększa wartość zasobu przy użyciu muteksu w celu wzajemnego wykluczenia.

Problem polega na tym, że wątek1 i wątek2 procesu serwera nie kończą się w miejscu, w którym powinny. W rzeczywistości utknęły one na pierwszym msgrcv() po wszystkich komunikatach increase/set0. Problem polega na tym, że dwa wątki nie są w stanie odsłuchać komunikatu o zakończeniu.

Próbowałem ustawić IPC_NOWAIT również dla pierwszego msgrcv ale nie działa

Odpowiedz

8

pan powołując się na wyścigu, jeden, że prawie nigdy nie wygrać.

Rzućmy okiem na pierwszym bloku:

do { 
    // Note the msg type:   vvvvvvvvvv 
    msgrcv(id_i, &msg, dimensione, INCREMENTA, 0); 

    // ... 

    // Note the msg type:   vvvvvvv 
    msgrcv(id_i, &msg, dimensione, TERMINA, IPC_NOWAIT); 
} 
while(msg.tipo != TERMINA); 

To drugie połączenie „msgrcv” w pętli to próba spojrzenia na wiadomości typu terminator, przed wami pętli z powrotem do góry i bloku, czeka na kolejną wiadomość INCREMENTA.

Rozważmy następujący ciąg wydarzeń:

Sender    Receiver 
    ---------------  ----------------- 
1      Call msgrcv with INCREMENTA. Block indefinitely 
2 Send 'INCREMENTA' 
3      msgrcv returns. Begin processing increment msg. 
4      Processing finshed. 
5      Call msgrcv with TERMINA. 
6      No TERMINA message found (queue empty), returns immediately. 
7      Go to top of loop. 
8      Call msgrcv with INCREMENTA. Block indefinitely 
9 Send 'TERMINA'  
10      Nothing happens because we're waiting for 'INCREMENTA'. 

Nie można spróbować zapytać kolejkę komunikatów w ten deseń. Jeśli zdarzenia 8 i 9 zostałyby odwrócone, Twoja logika by zadziałała - ale jest to stan wyścigu i taki, który prawdopodobnie często przegrywasz.

Zamiast tego, aby skorzystać z dowolnego rodzaju wiadomości, należy użyć msgrcv, a następnie po przeczytaniu wiadomości z kolejki dowiedzieć się, jaki rodzaj wiadomości został odebrany i jak ją odebrać. Jeśli podasz 0 dla parametru "msgtyp" na msgrcv, otrzymasz wszystkie wiadomości, a następnie będziesz mógł sobie z tym poradzić.

while(true) { 

     // Get any msg type:   vv 
     msgrcv(id_i, &msg, dimensione, 0, 0); 

     if (msg.tipo == TERMINA) { 
      break; 
     } 
     else { 
      // ... 
     } 
    } 
+0

Rozumiem. Odpowiedź została zaakceptowana. – EagleOne

Powiązane problemy