[C] Threads

Messaggioda giacomovicinanza » 15/05/2022, 14:05

Salve a tutti. Sto riscontrando un problema con questo esercizio praticamente non mi stampa i valori che sono contenuti nel buffer eppure non compare nessun tipo di errore nella schermata. Grazie mille a chi mi aiuterà.

https://onlinegdb.com/AA-NuPitX --> link del codice

Codice:
/*-------------------------------------------------------------------
 * Completare il programma fornito, completando il main e
 * implementando la funzione worker_thread.
 * Il main deve creare 100 thread figli, a cui deve passare
 * come parametri un intero da 1 a 100 (diverso per ogni thread figlio)
 * e un buffer che può contenere un singolo numero intero.
 * Una volta che i thread figli sono stati creati, il main deve
 * eseguire il seguente algoritmo:
 *         1. Ripeti per 100 volte i passi da 2 a 4.
 *           2. Aspetta che il buffer sia pieno.
 *           3. Preleva il valore contenuto nel buffer e stampalo a video
 *           4. Rendi il buffer vuoto.
 *
 * I thread figli, che eseguono la funzione worker_thread, devono svolgere
 * il seguente algoritmo:
 *           1. Aspetta 3 secondi.
 *           2. Aspetta che il buffer sia vuoto.
 *           3. Inserisci il numero ricevuto come parametro nel buffer.
 *           4. Rendi il buffer pieno.
 *
 * ESEMPIO
 * Lanciando il programma, l'ouput deve essere simile al seguente:
 *    Ho ricevuto il numero: 1
 *    Ho ricevuto il numero: 94
 *    Ho ricevuto il numero: 59
 *    Ho ricevuto il numero: 19
 *    Ho ricevuto il numero: 22
 *            . . . ( altri valori omessi per brevità ) . . .
 *    Ho ricevuto il numero: 39
 *    Ho ricevuto il numero: 40
 *    Ho ricevuto il numero: 51
 *    Ho ricevuto il numero: 56
 --------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#include <unistd.h>

#define NUM_WORKERS 100

/* Tipo da usare per il buffer */
typedef struct {
    int valore;   /* Valore contenuto nel buffer */
    bool pieno;   /* true se il buffer contiene un valore */
    pthread_mutex_t mutex; /* Mutex per l'accesso al buffer */
    pthread_cond_t  cond;  /* Condition per l'accesso al buffer */
} TBuffer;

/* Tipo da usare per passare i parametri ai thread figli */
typedef struct {
    int numero;   /* Numero assegnato al thread */
    TBuffer *buffer; /* Puntatore al buffer */
} TWorkerParam;


/* Prototipo della funzione dei thread figli */
void *worker_thread(void *param);

int main() {
    TBuffer buffer;
    buffer.pieno=false;
    pthread_mutex_init(&buffer.mutex, NULL);
    pthread_cond_init(&buffer.cond, NULL);
   
    pthread_mutex_t mutex; /* Mutex per la sincronizzazione */
    pthread_cond_t  cond;  /* Variabile condition per la sincronizzazione */
   
    TWorkerParam param[NUM_WORKERS];
    pthread_t tid[NUM_WORKERS];
    int i;
   
    for(i=0; i<NUM_WORKERS; i++) {
        if (pthread_create(&tid[i], NULL, worker_thread, &param[i])) {
            printf("Errore nella creazione di un thread\n");
            return -1;
        }
    }
   
        for(i=0; i<NUM_WORKERS; i++) {
        pthread_mutex_lock(&buffer.mutex);
        while (!buffer.pieno)
            pthread_cond_wait(&buffer.cond, &buffer.mutex);
        printf("Estratto il numero: %d\n", buffer.valore);
        buffer.pieno=false;
        pthread_cond_broadcast(&buffer.cond);
        pthread_mutex_unlock(&buffer.mutex);
    }
   
    for(i = 0; i < NUM_WORKERS; i++)
         pthread_join(tid[i], NULL);

    return 0;
}

/* Inserire l'implementazione della funzione worker_thread */
void *worker_thread(void *param) {
    TWorkerParam *p=(TWorkerParam *)param;
   
     pthread_mutex_lock(&p->buffer->mutex);
    while (p->buffer->pieno){
        sleep(3);
        pthread_cond_wait(&p->buffer->cond, &p->buffer->mutex);
        p->buffer->valore = p->numero;
        p->buffer->pieno = false;
        pthread_cond_signal(&p->buffer->cond);
        pthread_mutex_unlock(&p->buffer->mutex);
    }

    return NULL;
}
giacomovicinanza
Junior Member
Junior Member
 
Messaggio: 125 di 218
Iscritto il: 18/08/2021, 15:55

Re: [C] Threads

Messaggioda apatriarca » 15/05/2022, 17:05

La prima cosa che fai sia nel main che nei thread figli è chiamare lock sul mutex. Supponiamo che il primo a farlo sia il thread principale. Tutti gli altri thread sono quindi bloccati. A questo punto buffer.pieno == false e quindi entri nel ciclo e chiami pthread_cond_wait(&buffer.cond, &buffer.mutex). Questa istruzione ci dice di aspettare per la condizione rilasciando il mutex che può quindi essere bloccato da un altro thread. Supponiamo sia il thread 1. Il ciclo viene saltato perché p->buffer->pieno e quindi il thread finisce la sua esecuzione senza che nulla venga cambiato e non rilasciando il mutex. Non credo sia quello che dovrebbe fare..
apatriarca
Moderatore
Moderatore
 
Messaggio: 5673 di 10436
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Re: [C] Threads

Messaggioda Quinzio » 15/05/2022, 17:34

Qui sotto c'e' il codice messo a posto e che gira correttamente.

1) Il tuo programma ha dei warning che non devi trascurare. Intanto con la compilazione di default non tutti i warning sono attivi.
Per cui tu devi SEMPRE attivare i warning con queste flags.
-Wall -Wextra -pedantic-errors
Attivale e vedrai 2 warning molto preoccupanti.
Nota: i warnings sono avvertimenti da prendere sul serio, non vale il "si ma tanto compila". Ok ?

2) Ai singoli 3d passi una struttura che contiene l'ID del 3d e un puntatore alla struttura. Come mai tu non assegni nulla a quel puntatore ? Come fanno i "poveri" 3d a fare quello che devono fare se gli manca un riferimento al mutex, alla condition variable, ecc ?

3) Il 3d figlio deve scrivere qualcosa nella variabile di scambio, (value) e poi deve impostare pieno su true. I 3d figli riempiono il value con quacosa e il 3d main svuota la variabile value leggendola, e quindi imposta pieno su false, ovvero vuoto.

4) Il 3d figlio deve gestire la cond variable in modo diverso.
Deve:
- aspettare 3 sec, come da specifica.
- prendersi il mutex
- controllare che la variabile scambio sia vuota
- se non e' vuota si mette sin un loop infinito (la coppia while - pthread_cond_wait) e attende che la variabile scambio sia vuota, libera.
- quando si verificano le condizioni, il 3d figlio fa quello che deve fare impostando la variabile scambio
- liberare il mutex
- finire !!! uscire ! Il tuo 3d figlio non esce mai non termina mai la sua esecuzione.

4) Spero che tu abbia installato sul tuo pc un IDE di sviluppo come Eclipse o Code Blocks, in modo da usare comodamente il debugger. Attenzione pero' che quando lavori con i 3d e i processi multipli il debugger e' praticamente inutile (perche' ? prova a dare tu la risposta).
Quindi la tua unica speranza di debuggare e' di usare delle printf o altri stratagemmi. Nel mio codice trovi alcune printf disattivate.

5) Vedo che usate gia' puntatori, strutture, 3d, processi multipli e altro. Questi programmi anche se semplici sono gia' concettualmente non facili, per non dire impegnativi e in poco tempo, quando diventano dei veri programmi sono semplicemente infernali da debuggare e scrivere correttamente.
Per questo motivo devi capire il funzionamento di questi strumenti in modo chiaro e limpido come e' chiara e limpida l'acqua che bevi.
Purtroppo non vedo questo. Vedi anzi una certa confusione ed errori "di concetto", che nulla centrano con la comprensione del linguaggio C.
Se non ti chiarisci tutto al 100% ti troverai presto impantanato in un mare di guai e di errori.

Codice:
/*-------------------------------------------------------------------
 * Completare il programma fornito, completando il main e
 * implementando la funzione worker_thread.
 * Il main deve creare 100 thread figli, a cui deve passare
 * come parametri un intero da 1 a 100 (diverso per ogni thread figlio)
 * e un buffer che può contenere un singolo numero intero.
 * Una volta che i thread figli sono stati creati, il main deve
 * eseguire il seguente algoritmo:
 *         1. Ripeti per 100 volte i passi da 2 a 4.
 *           2. Aspetta che il buffer sia pieno.
 *           3. Preleva il valore contenuto nel buffer e stampalo a video
 *           4. Rendi il buffer vuoto.
 *
 * I thread figli, che eseguono la funzione worker_thread, devono svolgere
 * il seguente algoritmo:
 *           1. Aspetta 3 secondi.
 *           2. Aspetta che il buffer sia vuoto.
 *           3. Inserisci il numero ricevuto come parametro nel buffer.
 *           4. Rendi il buffer pieno.
 *
 * ESEMPIO
 * Lanciando il programma, l'ouput deve essere simile al seguente:
 *    Ho ricevuto il numero: 1
 *    Ho ricevuto il numero: 94
 *    Ho ricevuto il numero: 59
 *    Ho ricevuto il numero: 19
 *    Ho ricevuto il numero: 22
 *            . . . ( altri valori omessi per brevità ) . . .
 *    Ho ricevuto il numero: 39
 *    Ho ricevuto il numero: 40
 *    Ho ricevuto il numero: 51
 *    Ho ricevuto il numero: 56
 --------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
#include <unistd.h>

#define NUM_WORKERS 100

/* Tipo da usare per il buffer */
typedef struct {
   int valore; /* Valore contenuto nel buffer */
   bool pieno; /* true se il buffer contiene un valore */
   pthread_mutex_t mutex; /* Mutex per l'accesso al buffer */
   pthread_cond_t cond; /* Condition per l'accesso al buffer */
} TBuffer;

/* Tipo da usare per passare i parametri ai thread figli */
typedef struct {
   int numero; /* Numero assegnato al thread */
   TBuffer *buffer; /* Puntatore al buffer */
} TWorkerParam;

/* Prototipo della funzione dei thread figli */
void* worker_thread(void *param);

int main() {
   TBuffer glob_buffer;
   setvbuf(stdout, NULL, _IONBF, 0);
   glob_buffer.pieno = false;
   pthread_mutex_init(&glob_buffer.mutex, NULL);
   pthread_cond_init(&glob_buffer.cond, NULL);

   //pthread_mutex_t mutex; /* Mutex per la sincronizzazione */
   //pthread_cond_t cond; /* Variabile condition per la sincronizzazione */

   TWorkerParam param[NUM_WORKERS];
   pthread_t tid[NUM_WORKERS];
   int i;

   for (i = 0; i < NUM_WORKERS; i++) {
      param[i].buffer = &glob_buffer;
      param[i].numero = i;
   }
   for (i = 0; i < NUM_WORKERS; i++) {
      if (pthread_create(&tid[i], NULL, worker_thread, &param[i])) {
         printf("Errore nella creazione di un thread\n");
         return -1;
      } else {
         //printf("debug created 3d %d\n", i);
      }
   }

   for (i = 0; i < NUM_WORKERS; i++) {
      pthread_mutex_lock(&glob_buffer.mutex);
      while (!glob_buffer.pieno) {
         //printf("Main woke up\n");
         pthread_cond_wait(&glob_buffer.cond, &glob_buffer.mutex);
      }
      //printf("debug main pieno false\n");
      printf("Estratto il numero: %d\n", glob_buffer.valore);
      glob_buffer.pieno = false;
      pthread_cond_broadcast(&glob_buffer.cond);
      pthread_mutex_unlock(&glob_buffer.mutex);
   }

   for (i = 0; i < NUM_WORKERS; i++)
      pthread_join(tid[i], NULL);

   return 0;
}

/* Inserire l'implementazione della funzione worker_thread */
void* worker_thread(void *param) {
   TWorkerParam *p = (TWorkerParam*) param;

   sleep(3);
   pthread_mutex_lock(&p->buffer->mutex);
   while (p->buffer->pieno) {
      pthread_cond_wait(&p->buffer->cond, &p->buffer->mutex);
   }
   p->buffer->valore = p->numero;
   p->buffer->pieno = true;
   pthread_cond_signal(&p->buffer->cond);
   pthread_mutex_unlock(&p->buffer->mutex);
   //printf("debug end 3d %d\n", p->numero);

   return NULL;
}
Quinzio
Cannot live without
Cannot live without
 
Messaggio: 4902 di 10547
Iscritto il: 24/08/2010, 06:50

Re: [C] Threads

Messaggioda apatriarca » 15/05/2022, 18:52

Sono d'accordo con Quinzio che questi concetti sono certamente complicati da gestire se mancano le basi della programmazione C come abbiamo già visto con il programma di strutture dati (suppongo siano due esami diversi). In effetti la programmazione concorrente è complicata anche per programmatori esperti e le difficoltà nella comprensione di concetti di base (come nell'altra discussione il problema di dichiarare un array con una dimensione variabile non inizializzata) può solo complicare le cose.

@Quinzio: sarebbe comunque a mio parere utile per l'università italiana aggiornare un po' i programmi dei corsi che sembrano venire dagli anni 90.. Oltre al fatto di creare un esercizio in cui si hanno 100 threads ma solo uno che lavora.
apatriarca
Moderatore
Moderatore
 
Messaggio: 5674 di 10436
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Re: [C] Threads

Messaggioda giacomovicinanza » 16/05/2022, 15:15

Grazie mille per avermi fatto notare gli errori.
giacomovicinanza
Junior Member
Junior Member
 
Messaggio: 126 di 218
Iscritto il: 18/08/2021, 15:55


Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite