/* pthreads_test.c Jeff Ondich, 6 March 2022 A simple threaded program that lets us see a typical use of threads. One thread is an extremely simple user interface thread (printing a prompt and waiting for a newline), while the other is a trivial "computational" thread, counting until the UI thread tells it to stop. The two threads communicate through the global variable time_to_quit. To compile on mantis: gcc -Wall -o pthreads_test pthreads_test.c -lpthread On some systems, you don't need to link the pthread library explicitly, so it looks like this instead: gcc -Wall -o pthreads_test pthreads_test.c */ #include #include #include #include // The shared variable and its lock bool time_to_quit; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // The thread start routines void *ui_thread_main(void *arg); void *worker_thread_main(void *arg); int main() { pthread_t ui_thread, worker_thread; // Don't need to lock it because we only have the main thread so far. time_to_quit = false; // Spawn the threads printf("[main] Creating the threads\n"); fflush(stdout); if (pthread_create(&ui_thread, NULL, ui_thread_main, 0) != 0) { perror("[main] Can't create UI thread."); exit(1); } if (pthread_create(&worker_thread, NULL, worker_thread_main, 0) != 0) { perror("[main] Can't create worker thread."); exit(1); } // Wait for the threads to return. If you don't do so, the main // thread will return from main() and thus shut down the whole process, // including both threads. if (pthread_join(ui_thread, NULL) != 0) { perror("[main] Can't join UI thread."); exit(1); } if (pthread_join(worker_thread, NULL) != 0) { perror("[main] Can't join worker thread."); exit(1); } printf("[main] Bye!\n"); fflush(stdout); return 0; } void *ui_thread_main(void *arg) { char buffer[100]; printf("[UI thread] Hit Enter when you're ready to be done\n"); fflush(stdout); if (fgets(buffer, 100, stdin) == NULL) { fprintf(stderr, "[UI thread] Problem taking input. Try again.\n"); } // Alert the worker thread that it should stop counting now. // Don't try to use the shared/global variable without locking it. pthread_mutex_lock(&lock); time_to_quit = true; pthread_mutex_unlock(&lock); printf("[UI thread] All done\n"); fflush(stdout); return NULL; } void *worker_thread_main(void *arg) { printf("[Worker thread] Let's count!\n"); fflush(stdout); int should_quit; long counter = 0; while (1) { // Make a local copy of the shared variable while it's locked. pthread_mutex_lock(&lock); should_quit = time_to_quit; pthread_mutex_unlock(&lock); if (should_quit) { break; } counter++; } printf("[Worker thread] I counted this high: %ld\n", counter); fflush(stdout); return NULL; }