#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * D06 il programma crea un thread "lavoratore" che effettua il seguente: ciclo: - il thread si mette in attesa; - il thread principale "fornisce" il "materiale" su cui il thread lavorerà una volta svegliato; - il thread viene svegliato ed inizia a lavorare sul "materiale"; - il thread produce il risultato e lo "restituisce"; - il thread torna a "dormire"; * */ // scrive in buffer il timestamp in formato: secondi.microsecondi (tempo dal boot del calcolatore) char * get_timestamp(char * buffer, int buffer_len) { if (buffer_len < 32) { printf("buffer è troppo piccolo"); exit(1); } struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { perror("clock_gettime"); exit(EXIT_FAILURE); } sprintf(buffer, "%6ld.%06ld", ts.tv_sec, ts.tv_nsec / 1000); return buffer; } typedef struct { sem_t work_start; sem_t work_end; int input; int output; // char * data; // int data_len; // // char * result; // int result_len; } thread_param; void * worker_thread_function(void * arg) { char buffer[32]; thread_param * param = arg; printf("[worker %s] thread avviato\n", get_timestamp(buffer, 32)); while (1) { printf("[worker %s] vado a dormire in attesa dei dati su cui lavorare\n", get_timestamp(buffer, 32)); if (sem_wait(¶m->work_start) != 0) { perror("sem_wait"); exit(1); } printf("[worker %s] ora inizio a lavorare sui dati ricevuti...\n", get_timestamp(buffer, 32)); // facciamo qualcosa... int counter = 0; for (int i = 0; i < param->input; i++) { counter++; } // "ok fatto!" // mettiamo a disposizione il risultato: param->output = counter; printf("[worker %s] ho messo a disposizione il risultato, ora lo segnalo\n", get_timestamp(buffer, 32)); if (sem_post(¶m->work_end) != 0) { perror("sem_post"); exit(1); } printf("[worker %s] ho segnalato che i risultati sono pronti, ora torno a 'dormire'\n", get_timestamp(buffer, 32)); } return NULL; } int main() { char buffer[32]; pthread_t worker_thread; thread_param worker_param; if (sem_init(&worker_param.work_start, 0, 0) != 0) { perror("sem_init"); exit(1); } if (sem_init(&worker_param.work_end, 0, 0) != 0) { perror("sem_init"); exit(1); } if (pthread_create(&worker_thread, NULL, worker_thread_function, &worker_param) != 0) { perror("pthread_create"); exit(1); } for (int i = 0; i < 2; i++) { printf("[main %s] preparo i prossimi dati...\n", get_timestamp(buffer, 32)); worker_param.input = 12340000 + i; printf("[main %s] dati pronti per il worker thread! ora lo 'sveglio'\n", get_timestamp(buffer, 32)); if (sem_post(&worker_param.work_start) != 0) { perror("sem_post"); exit(1); } printf("[main %s] aspetto l'output del worker thread\n", get_timestamp(buffer, 32)); if (sem_wait(&worker_param.work_end) != 0) { perror("sem_wait"); exit(1); } printf("[main %s] il risultato del worker thread è pronto: %d\n", get_timestamp(buffer, 32), worker_param.output); sleep(1); } printf("[main %s] faccio terminare il thread\n", get_timestamp(buffer, 32)); // nuova funzione: fa terminare il pthread specificato dal tid if (pthread_cancel(worker_thread) != 0) { perror("pthread_cancel"); } if (pthread_join(worker_thread, NULL) != 0) { perror("pthread_join"); } printf("[main %s] bye\n", get_timestamp(buffer, 32)); return 0; }