/*********************************************************************** Demonstrate multithreading using the Pthreads library, and show that errno is handled correctly between threads. This version does NOT use locks around output statements. Tests have been run on FreeBSD (IA-32) GNU/Linux (Alpha, AMD64, IA-32, IA-64, PowerPC-32, PowerPC-64, SPARC) IRIX (MIPS) Mac OS X (IA-32 and PowerPC-32) MirBSD (IA-32) NetBSD (IA-32) OpenBSD (IA-32) Solaris (AMD64, IA-32, SPARC) with both -lm and -lmcw. With -lm, output is always correct. With -lmcw, serious output mixing occurs on IRIX, and minor mixing on FreeBSD. For a tutorial on Pthreads, see POSIX Threads Programming Blaise Barney, Lawrence Livermore National Laboratory https://computing.llnl.gov/tutorials/pthreads/ The standard is available here: IEEE Std 1003.1, 2004 Edition http://www.unix.org/version3/ieee_std.html Usage: c99 [-DMAXTEST=nnnnnn] [-DMAXTHREADS=nn] thread1.c -lpthread -lm && ./a.out cc [-DMAXTEST=nnnnnn] [-DMAXTHREADS=nn] thread1.c -lpthread -lm && ./a.out gcc [-DMAXTEST=nnnnnn] [-DMAXTHREADS=nn] thread1.c -lpthread -lm && ./a.out dgcc [-DMAXTEST=nnnnnn] [-DMAXTHREADS=nn] thread1.c -lpthread ../libmcw.a && ./a.out gcc [-DMAXTEST=nnnnnn] [-DMAXTHREADS=nn] thread1.c -lpthread ../libmcw.a && ./a.out Typical default output: ------------------------------------------------------------------------ The only output should be two begin/end lines from each thread. Any assertion failure means that errno has received an unexpected value. ------------------------------------------------------------------------ Begin normal thread 0 Begin underflow thread 2 Begin overflow thread 1 End normal thread 0 Begin normal thread 3 End normal thread 3 Begin overflow thread 4 Begin underflow thread 5 Begin normal thread 6 Begin overflow thread 7 End normal thread 6 End underflow thread 5 End underflow thread 2 End overflow thread 1 End overflow thread 4 End overflow thread 7 [19-Aug-2010] ***********************************************************************/ #include #include #include #include #include #include #include #if !defined(MAXTEST) #define MAXTEST 1000000 #endif #if !defined(MAXTHREAD) #define MAXTHREAD 8 #endif void work_normal(long int id) { int k; (void)printf("Begin normal thread %ld\n", id); (void)fflush(stdout); for (k = 0; k < MAXTEST; ++k) { volatile double x, y; x = (double)k; errno = 0; y = sqrt(x); assert(errno == 0); } (void)printf("End normal thread %ld\n", id); (void)fflush(stdout); } void work_overflow(long int id) { int k; (void)printf("\tBegin overflow thread %ld\n", id); (void)fflush(stdout); for (k = 0; k < MAXTEST; ++k) { volatile double x, y; x = DBL_MAX; errno = 0; y = exp(x); if ( (errno != ERANGE) && (errno != 0) ) { (void)fprintf(stderr, "overflow thread sets errno = %d\t", errno); perror("perror() says errno means"); (void)fflush(stderr); assert((errno == ERANGE) || (errno == 0)); } } (void)printf("\tEnd overflow thread %ld\n", id); (void)fflush(stdout); } void work_underflow(long int id) { int k; (void)printf("\t\tBegin underflow thread %ld\n", id); (void)fflush(stdout); for (k = 0; k < MAXTEST; ++k) { volatile double x, y; x = DBL_MIN; errno = 0; y = exp(x); if ( (errno != ERANGE) && (errno != 0) ) { (void)fprintf(stderr, "underflow thread sets errno = %d\t", errno); perror("perror() says errno means"); (void)fflush(stderr); assert((errno == ERANGE) || (errno == 0)); } } (void)printf("\t\tEnd underflow thread %ld\n", id); (void)fflush(stdout); } void * thread_main(void *thread_id) { long int id; id = (long int)thread_id; switch (id % 3) { default: /* FALL THROUGH */ case 0: work_normal(id); break; case 1: work_overflow(id); break; case 2: work_underflow(id); break; } pthread_exit(NULL); return ((void *)NULL); /* NOT REACHED */ } int main(void) { pthread_t threads[MAXTHREAD]; int k, rc; (void)printf("------------------------------------------------------------------------\n"); (void)printf("The only output should be two begin/end lines from each thread.\n"); (void)printf("Any assertion failure means that errno has received an unexpected value.\n"); (void)printf("------------------------------------------------------------------------\n\n"); for (k = 0; k < MAXTHREAD; ++k) { /* ** Ignore harmless compiler warnings ** "cast to pointer from integer of different size" ** for last argument to pthread_create(). */ rc = pthread_create(&threads[k], NULL, thread_main, (void *)k); if (rc != 0) { (void)printf("ERROR: return code for thread %d [%ld] from pthread_create() = %d\n", k, (long int)threads[k], rc); return (EXIT_FAILURE); } } pthread_exit(NULL); (void)printf("Unexpected return from pthread_exit()\n"); /* NOT REACHED */ return (EXIT_SUCCESS); /* NOT REACHED */ }