/* progress-bar.c Jeff Ondich, 2 June 2019 Keyboard setup Code adapted from http://www.linux-sxs.org/programming/kbhit.html, which in turn adapted it from "Beginning Linux Programming" by Neil Matthew and Richard Stones, Wrox Press. */ #include #include #include #include #include // for read() #include void initialize_keyboard(); void restore_keyboard(); void *workerThreadMain(void *arg); void *progressThreadMain(void *arg); pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER; int gPrimeCount = 0; int gProgress = 0; int gProgressLimit = 0; int main() { gProgressLimit = 1000000; fprintf(stderr, "We're counting the prime numbers <= %d\n", gProgressLimit); fprintf(stderr, "Hit X to cancel\n"); pthread_t workerThread, progressThread; if (pthread_create(&progressThread, NULL, progressThreadMain, 0) != 0) { perror("Can't create progress thread"); exit(1); } if (pthread_create(&workerThread, NULL, workerThreadMain, 0) != 0) { perror("Can't create worker thread"); exit(1); } initialize_keyboard(); char ch = '\0'; while (gProgress < gProgressLimit && tolower(ch) != 'x') { read(0, &ch, 1); } fputc('\n', stderr); restore_keyboard(); return 0; } // Returns true (1) if n is prime, false (0) otherwise. // Uses a super-slow algorithm because we just want // it to take a long time. int isPrime(int n) { for (int k = 2; 2 * k <= n; k++) { if (n % k == 0) { return 0; } } return 1; } void *workerThreadMain(void *arg) { fprintf(stderr, "Worker thread starting\n"); gPrimeCount = 1; for (int k = 3; k <= gProgressLimit; k += 2) { gProgress = k; if (isPrime(k)) { pthread_mutex_lock(&gLock); gPrimeCount++; pthread_mutex_unlock(&gLock); } } return NULL; } void *progressThreadMain(void *arg) { int previousBoxCount = 0; while (gProgress < gProgressLimit) { float percentage = 100.0 * (float)gProgress / (float)gProgressLimit; int progressBoxCount = (int)(percentage / 2.0); if (progressBoxCount != previousBoxCount) { fprintf(stderr, "(%02.1f) |", percentage); for (int k = 0; k < 50; k++) { if (k < progressBoxCount) { fputc('x', stderr); } else { fputc(' ', stderr); } } fprintf(stderr, "|\r"); previousBoxCount = progressBoxCount; } } fprintf(stderr, "\n# primes less than or equal to %d: %d\n", gProgressLimit, gPrimeCount); return NULL; } // Keyboard management static struct termios initial_settings, new_settings; void initialize_keyboard() { tcgetattr(0, &initial_settings); new_settings = initial_settings; new_settings.c_lflag &= ~ICANON; new_settings.c_lflag &= ~ECHO; new_settings.c_lflag &= ~ISIG; new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; tcsetattr(0, TCSANOW, &new_settings); } void restore_keyboard() { tcsetattr(0, TCSANOW, &initial_settings); }