-
-
Save akolybelnikov/6cec5d38c5684875155aaff6e58febf8 to your computer and use it in GitHub Desktop.
C11 code to have a POSIX multithreaded application which signal work completion via a condition variable, and then terminate.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <unistd.h> | |
#include <stdbool.h> | |
#include <pthread.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#define NUM_THREADS 10 | |
pthread_mutex_t cv_mutex; | |
pthread_cond_t notification_cv; | |
pthread_t threads[NUM_THREADS]; | |
bool allfinished = false; | |
void *worker(void *arg) { | |
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | |
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |
int loop = 0; | |
while (true) { | |
printf("iteration %d\n", loop); | |
++loop; | |
/* Do some "work": */ | |
; | |
pthread_mutex_lock(&cv_mutex); | |
if (loop > 5) { /* Simulate "work end" */ | |
allfinished = true; | |
pthread_cond_broadcast(¬ification_cv); | |
pthread_mutex_unlock(&cv_mutex); | |
pthread_exit(NULL); | |
} | |
pthread_mutex_unlock(&cv_mutex); | |
} | |
pthread_exit(NULL); | |
} | |
void *master(void *t) { | |
/* Lock mutex and wait for signal. */ | |
pthread_mutex_lock(&cv_mutex); | |
while (!allfinished) | |
pthread_cond_wait(¬ification_cv, &cv_mutex); | |
printf("master: woken up.\n"); | |
pthread_mutex_unlock(&cv_mutex); | |
for (size_t i = 0; i < NUM_THREADS; ++i) { | |
pthread_cancel(threads[i]); | |
} | |
pthread_exit(NULL); | |
} | |
int main(int argc, char *argv[]) { | |
pthread_attr_t attr; | |
/* Initialize mutex and condition variable objects */ | |
pthread_mutex_init(&cv_mutex, NULL); | |
pthread_cond_init(¬ification_cv, NULL); | |
/* For portability, explicitly create threads in a joinable state */ | |
pthread_attr_init(&attr); | |
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); | |
pthread_t s; | |
pthread_create(&s, &attr, master, NULL); | |
for(size_t i = 0; i < sizeof threads / sizeof *threads; ++i) { | |
if (!pthread_create (&threads[i], &attr, worker, NULL) ) { | |
printf("worker %zu created\n", i); | |
} | |
} | |
/* Wait for all threads to complete. This will not wait forever because the master | |
* thread will cancel all of the workers: | |
*/ | |
for (size_t i = 0; i < sizeof threads / sizeof *threads; ++i) { | |
pthread_join(threads[i], NULL); | |
printf("worker %zu done\n", i); | |
} | |
pthread_join(s, NULL); | |
printf("master done\n"); | |
/* Clean up and exit */ | |
pthread_attr_destroy(&attr); | |
pthread_mutex_destroy(&cv_mutex); | |
pthread_cond_destroy(¬ification_cv); | |
pthread_exit(NULL); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment