Domanda

Sto lavorando su un progetto e cercando di utilizzare pthread_cond_wait() e pthread_cond_signal() per sincronizzare due thread.

Il mio codice simile a questa:

pthread_mutex_t lock_it = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t write_it = PTHREAD_COND_INITIALIZER;

   int main(int argc, char**argv)
  {

     pthread_t t_send_segments, t_recv_acks;

     pthread_create(&t_send_segments, NULL, send_segments, (void*)NULL);
     pthread_create(&t_recv_acks,     NULL, recv_acks,     (void*)NULL);

     pthread_join(t_recv_acks, (void**)NULL);

     pthread_mutex_destroy(&lock_it);
     pthread_cond_destroy(&write_it);
}

 void* send_segments(void *v) {
    for(;;) {
       pthread_mutex_lock(&lock_it);
       printf("s1\n");
       printf("s2\n");
       pthread_cond_wait(&write_it, &lock_it);
       printf("s3\n");
       printf("s4\n");
       printf("s5\n"); 
       pthread_mutex_unlock(&lock_it);
    }
    return 0;
 }

 void* recv_acks(void *v) {
    for(;;) {
       pthread_mutex_lock(&lock_it);
       printf("r1\n");
       pthread_cond_signal(&write_it);
       printf("r2\n");
       pthread_mutex_unlock(&lock_it);
    }  
    return 0;
 }

Il risultato atteso è:

s1
s2
r1
s3
s4
s5
s1
s2
r2
r1
s3
s4
s5

(etc)

La mia uscita non segue questo schema a tutti. Chiaramente ho un errore logico da qualche parte, ma io non sto capendo dove. Perché l'recv_acks() filo sempre rendimento quando si colpisce il cond_wait() - dal momento che la <=> esegue sempre prima (a causa del l'ordine in cui creo i fili) e il <= > esegue sempre dalla sua nella sezione critica?

È stato utile?

Soluzione

La funzione pthread_cond_signal non provoca il thread corrente per produrre e non rilascia il mutex. Tutto ciò che fa è riavviare un filo che si è sospesa sulla condizione via pthread_cond_wait. Questo significa solo il filo risvegliato è disponibile per la pianificazione, non farla eseguire immediatamente. Il filo-scheduler pianificarlo in futuro.

Inoltre, proprio perché la s-thread è stato risvegliato e si contendono il mutex, questo non significa che si sta andando a ottenere il mutex successivo. Mutex non sono necessariamente giusto per tutte le discussioni che ne hanno fatto richiesta. Secondo la pagina pthread_mutex dell'uomo: "pthread_mutex_lock blocca la data mutex Se il mutex è attualmente sbloccato, esso viene bloccato e di proprietà del thread chiamante, e <=> restituisce immediatamente.". Così la R-thread può girare nel proprio circuito di parecchie volte, felicemente sbloccare e ribloccare il mutex più volte prima di essere scambiato dallo scheduler. Ciò significa che l's-filo otterrà solo una possibilità al mutex se lo scheduler accade per interrompere il r-filo durante il breve tempo in cui ha rilasciato il mutex.

Per ottenere l'output desiderato, entrambi i fili dovranno controllare la loro esecuzione con una condizione e di segnalare l'un l'altro prima di sospendere stessi. Tuttavia, questo può o non può essere quello che si vuole realmente a che fare con il vostro vero e proprio progetto.

Un'altra nota: in realtà non importa in che ordine si è creato i fili in Creazione di un filo non cede il filo creazione.. Quindi il thread principale sarà probabilmente creare entrambi i fili prima che uno ottiene in programma, e la pianificazione dei thread è libero di programmare uno di loro per l'esecuzione successiva. Se il s-thread viene eseguito prima sulla vostra piattaforma, che sembra appena essere il comportamento implementazione della piattaforma e non è qualcosa che dovrebbe essere fatto valere.

Altri suggerimenti

Mi pare di ricordare letto da qualche parte che pthread_cond_signal() non effettivamente causare il thread di cedere immediatamente. Poiché pthread_cond_wait() non rilascia il blocco, il filo che chiama deve continuare l'esecuzione fino a quando non rilasciare il blocco, e solo poi vuol cedere e permettere il filo segnalato al ritorno da <= >.

Se questo è il caso, allora penso che l'output sarà simile

s1
s2
r1
r2
s3
s4
s5

, ecc .... se non è così, potrebbe essere necessario modificare l'uscita effettiva nella sua domanda per ottenere una risposta precisa.

Si sta facendo un uso sbagliato di condizioni. Non ho capito esattamente quello che vuoi, ma ciò che si sta cercando di fare assomiglia molto a un tipico problema di sincronizzazione chiamato il problema produttore / consumatore che può essere implementato con condizioni come ho fatto io dopo.

Si dovrebbe avere un'occhiata a questo per capire come vengono utilizzate le condizioni. Il problema è il seguente: Ho due fili, dati una scrittura in un buffer di dimensione fissa e un'altra lettura di dati dal buffer. Il primo filo non può scrivere più dati se il buffer è pieno, il secondo non può leggere se il buffer è vuoto.

#include <stdlib.h>
#include <stdio.h>

#include <pthread.h>

#define BUFFER_SIZE 4 

int buffer_nb_entries = 0; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void send(){
for(;;){
  pthread_mutex_lock(&mutex);
  while( buffer_nb_entries == BUFFER_SIZE) /* If buffer is full, then wait */
    pthread_cond_wait(&cond, &mutex); 

  /* Here I am sure that buffer is not full */
  printf("sending\n"); 
  buffer_nb_entries++;

  pthread_cond_signal(&cond); // signal that the condition has changed. 
  pthread_mutex_unlock(&mutex); 
 }
}

void receive(){
  for(;;){
    pthread_mutex_lock(&mutex); 
    while(buffer_nb_entries == 0)
      pthread_cond_wait(&cond, &mutex);
    /* Here I am sure that buffer is not empty */
    printf("receiving\n");
    buffer_nb_entries--; 
    pthread_cond_signal(&cond); 
    pthread_mutex_unlock(&mutex); 
  }

}

int main(){
  pthread_t s, r; 

  pthread_create(&s, NULL, (void *(*)(void*))send, NULL); 
  pthread_create(&r, NULL, (void *(*)(void*))receive, NULL); 

  pthread_join(s, NULL); 

}

Si noti che è necessario verificare di qualcosa prima di chiamare pthread_cond_wait (), se non, e se si segnale la funzione è stato chiamato prima, allora si può dormire per sempre.

Credo che il tuo problema è venuta dal tentativo di utilizzare una serratura per troppe cose. Si dovrebbe utilizzare solo un blocco per 1 cosa, in questo modo non v'è alcuna confusione su ciò che si sta aspettando. Suggerisco l'aggiunta di un secondo blocco per il segnale di scrittura. Inoltre, si dovrebbe aggiungere un secondo cond_wait per il secondo gruppo di messaggi. Se non lo fai, l'ordine che le cose funzionano in sarà casuale. Ecco la mia versione modificata del programma:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define NUM_MESSAGES 3
int messages = 0;
void * send_segments(void *);
void * recv_acks(void *v);
pthread_mutex_t lock_it = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t write_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;

   int main(int argc, char**argv)
  {

     pthread_t t_send_segments, t_recv_acks;

     pthread_create(&t_send_segments, NULL, send_segments, (void*)NULL);
     pthread_create(&t_recv_acks,     NULL, recv_acks,     (void*)NULL);

     pthread_join(t_recv_acks, (void**)NULL);
     pthread_join(t_send_segments, (void**)NULL);

     //pthread_mutex_destroy(&lock_it);
     //pthread_cond_destroy(&write_it);
}

 void* send_segments(void *v) {
    for(;;) {
       pthread_mutex_lock(&lock_it);
       printf("s1\n");
       printf("s2\n");
       pthread_mutex_unlock(&lock_it);

       // wait for other thread
       pthread_mutex_lock(&write_mutex);
       pthread_cond_wait(&write_cond, &write_mutex);
       pthread_mutex_unlock(&write_mutex);

       pthread_mutex_lock(&lock_it);
       printf("s3\n");
       printf("s4\n");
       printf("s5\n"); 
       pthread_mutex_unlock(&lock_it);

       // wait for other thread
       pthread_mutex_lock(&write_mutex);
       pthread_cond_wait(&write_cond, &write_mutex);
       pthread_mutex_unlock(&write_mutex);

       if (messages > NUM_MESSAGES) return( NULL );
    }
    return 0;
 }


 void* recv_acks(void *v) {
    for(;;) {
       // write first response
       pthread_mutex_lock(&lock_it);
       printf("r1\n");
       pthread_mutex_unlock(&lock_it);

       // signal other thread
       pthread_mutex_lock(&write_mutex);
       pthread_cond_signal(&write_cond);
       pthread_mutex_unlock(&write_mutex);

       // write second response
       pthread_mutex_lock(&lock_it);
       printf("r2\n\n");
       // increment count before releasing lock, otherwise the other thread
       // will be stuck waiting for a write_cond signal
       messages++;
       pthread_mutex_unlock(&lock_it);

       // signal other thread
       pthread_mutex_lock(&write_mutex);
       pthread_cond_signal(&write_cond);
       pthread_mutex_unlock(&write_mutex);

       if (messages > NUM_MESSAGES) return(NULL);
    } 
    return 0;
 }

Se corro questo programma, ottengo il seguente output (nota che ho aggiunto un secondo ritorno a capo dopo r2 per chiarezza):

leif@indurain:~/tmp$ ./test
s1
s2
r1
s3
s4
s5
r2

s1
s2
r1
s3
s4
s5
r2

s1
s2
r1
s3
s4
s5
r2

s1
s2
r1
s3
s4
s5
r2

leif@indurain:~/tmp$ 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top