pluto% num pthread.c 1 /* pthread.c 2 * This is a simple example to show POSIX thread creation and waiting for 3 * a normal termination of sibling threads. 4 * This program creates threads depending on the number of command-line 5 * arguments given (up to MAX). Each thread will print the actual value 6 * of the command-line argument it has received in turn. 7 * Some pthread APIs 8 * 1. to create a thread 9 * int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 10 * void *(*start_routine)(void *), void *arg); 11 * return status 0: success, nonzero: failure 12 * 2. to wait for a thread to terminate 13 * int pthread_join(pthread_t thread, void **value_ptr); 14 * return status 0: success, nonzero: failure 15 * 3. to get calling thread's tid 16 * pthread_t pthread_self(void); 17 * To compile: gcc pthread.c -lpthread 18 * Sam Hsu (11/11/10) 19 */ 20 #define _REENTRANT 21 #include 22 #include 23 #include 24 #define MAX 10 25 int main(int argc, char *argv[]) 26 { 27 int i, status, *status_ptr = &status; 28 pthread_t thread[MAX]; 29 void *prt_arg(void *); 30 for (i = 0; i < argc-1; i++) { /* creating threads */ 31 if (pthread_create(&thread[i], NULL, prt_arg, (void *)argv[i+1]) != 0) { 32 fprintf(stderr, "Failed to create a thread\n"); 33 exit(1); 34 } 35 } 36 for (i = 0; i < argc-1; i++) { /* waiting for thread terminations */ 37 if (pthread_join(thread[i], (void **)status_ptr) != 0) { 38 fprintf(stderr, "Failed to terminate a thread\n"); 39 exit(2); 40 } 41 printf("Thread %u returns %d\n", thread[i], status); 42 } 43 return(0); 44 } 45 void *prt_arg(void *arg) 46 { 47 pthread_t tid = pthread_self(); /* to get tid for itself */ 48 printf("Thread %u got \"%s\"\n", tid, (char *)arg); 49 return (void *)NULL; 50 } pluto% pthread A thread example Thread 3086834576 got "A" Thread 3076344720 got "thread" Thread 3065854864 got "example" Thread 3086834576 returns 0 Thread 3076344720 returns 0 Thread 3065854864 returns 0 pluto% num ptmutex.c 1 /* ptmutex.c 2 * This program illustrates thread synchronization using mutex 3 * Three threads: 4 * 1. DM thread: Reads from disk to memory buffer (inbuf) 5 * While not EOF { 6 * lock DM lock 7 * read from disk to inbuf, one block at a time 8 * unlock DM lock 9 * } 10 * 2. MM thread: Move data from inbuf to outbuf 11 * While something is in inbuf { 12 * lock both DM and MS locks 13 * copy from inbuf to outbuf, one block at a time 14 * unlock DM and MS locks 15 * } 16 * 3. MS thread: Writes from memory buffer (outbuf) to screen 17 * While something is in outbuf { 18 * lock MS lock 19 * write to screen, one block at a time 20 * unlock MS lock 21 * } 22 * To compile: gcc ptmutex.c -lpthread 23 * Sam Hsu (11/12/10) 24 */ 25 #define _REENTRANT 26 #include 27 #include 28 #include 29 #include 30 #include 31 #include 32 #define buffer_t struct buffer 33 struct buffer { 34 int siz; 35 char buf[BUFSIZ]; 36 }; 37 enum {FALSE = 0, TRUE = 1}; 38 int fdes, inflag = FALSE, outflag = FALSE; 39 ssize_t nread = 1; 40 buffer_t inbuf = {0, ""}, outbuf = {0, ""}; 41 pthread_mutex_t DMlock = PTHREAD_MUTEX_INITIALIZER, 42 MMlock = PTHREAD_MUTEX_INITIALIZER, 43 MSlock = PTHREAD_MUTEX_INITIALIZER; 44 main(int argc, char *argv[]) 45 { 46 int status, *status_ptr = &status; 47 pthread_t dmthread, mmthread, msthread; 48 void *DMthread(void *), *MMthread(void *), *MSthread(void *); 49 if ((fdes = open(argv[1], O_RDONLY)) == -1) { 50 fprintf(stderr, "failed to open %s\n", argv[1]); 51 exit(1); 52 } 53 if (pthread_create(&dmthread, NULL, DMthread, (void *)NULL) != 0) { 54 fprintf(stderr, "failed to create DMthread\n"); 55 exit(2); 56 } 57 if (pthread_create(&mmthread, NULL, MMthread, (void *)NULL) != 0) { 58 fprintf(stderr, "failed to create MMthread\n"); 59 exit(3); 60 } 61 if (pthread_create(&msthread, NULL, MSthread, (void *)NULL) != 0) { 62 fprintf(stderr, "failed to create MSthread\n"); 63 exit(4); 64 } 65 if (pthread_join(dmthread, (void **)status_ptr) != 0) { 66 fprintf(stderr, "failed to terminate DMthread\n"); 67 exit(5); 68 } 69 if (pthread_join(mmthread, (void **)status_ptr) != 0) { 70 fprintf(stderr, "failed to terminate MMthread\n"); 71 exit(6); 72 } 73 if (pthread_join(msthread, (void **)status_ptr) != 0) { 74 fprintf(stderr, "failed to terminate MSthread\n"); 75 exit(7); 76 } 77 pthread_mutex_destroy(&DMlock); /* assume no error */ 78 pthread_mutex_destroy(&MMlock); 79 pthread_mutex_destroy(&MSlock); 80 close(fdes); 81 return(0); 82 } /* main */ 83 void *DMthread(void *dummy) 84 { 85 int err; 86 while (nread) { /* while not EOF */ 87 while (inflag == TRUE) { /* inbuf data not copied out yet */ 88 sched_yield(); /* give up CPU to other threads */ 89 } 90 if ((err = pthread_mutex_lock(&DMlock)) != 0) { 91 fprintf(stderr, "DMthread lock failed %d\n", err); 92 pthread_exit((void *)8); 93 } 94 if ((nread = read(fdes, inbuf.buf, BUFSIZ)) > 0) { /* assume no error */ 95 inbuf.siz = (int)nread; 96 inflag = TRUE; /* new data in inbuf */ 97 } 98 if ((err = pthread_mutex_unlock(&DMlock)) != 0) { 99 fprintf(stderr, "DMthread unlock failed %d\n", err); 100 pthread_exit((void *)9); 101 } 102 } 103 pthread_exit((void *)NULL); 104 } /* DMthread */ 105 void *MMthread(void *dummy) 106 { 107 int err; 108 while (nread != 0 || inflag == TRUE) { /* something in inbuf */ 109 if (outflag == TRUE) { /* outbuf data not processed yet */ 110 sched_yield(); /* let other threads go first */ 111 continue; /* in case it is the last block */ 112 } 113 if ((err = pthread_mutex_lock(&DMlock)) != 0) { 114 fprintf(stderr, "MMthread lock failed %d\n", err); 115 pthread_exit((void *)10); 116 } 117 if ((err = pthread_mutex_lock(&MSlock)) != 0) { 118 fprintf(stderr, "MMthread lock failed %d\n", err); 119 pthread_exit((void *)11); 120 } 121 /* copy inbuf to outbuf, assume OK */ 122 memcpy(outbuf.buf, inbuf.buf, (outbuf.siz=inbuf.siz)); 123 inbuf.siz = 0; /* to avoid copy twice */ 124 outflag = TRUE; /* indicate new data in outbuf */ 125 inflag = FALSE; /* indicate data in inbuf copied */ 126 if ((err = pthread_mutex_unlock(&DMlock)) != 0) { 127 fprintf(stderr, "MMthread unlock failed %d\n", err); 128 pthread_exit((void *)12); 129 } 130 if ((err = pthread_mutex_unlock(&MSlock)) != 0) { 131 fprintf(stderr, "MMthread unlock failed %d\n", err); 132 pthread_exit((void *)13); 133 } 134 } 135 pthread_exit((void *)NULL); 136 } /* MMthread */ 137 void *MSthread(void *dummy) 138 { 139 int err; 140 while (nread != 0 || outflag == TRUE || inflag == TRUE) { 141 if (outflag == FALSE) { 142 sched_yield(); /* let others go first */ 143 continue; 144 } 145 if ((err = pthread_mutex_lock(&MSlock)) != 0) { 146 fprintf(stderr, "MSthread lock failed %d\n", err); 147 pthread_exit((void *)14); 148 } 149 write(STDOUT_FILENO, outbuf.buf, outbuf.siz); /* assume no error */ 150 outbuf.siz = 0; /* to avoid display twice */ 151 outflag = FALSE; /* outbuf emptied */ 152 if ((err = pthread_mutex_unlock(&MSlock)) != 0) { 153 fprintf(stderr, "MSthread unlock failed %d\n", err); 154 pthread_exit((void *)15); 155 } 156 } 157 pthread_exit((void *)NULL); 158 } /* MSthread */ pluto% ptmutex ptmutex.c /* ptmutex.c * This program illustrates thread synchronization using mutex * Three threads: * 1. DM thread: Reads from disk to memory buffer (inbuf) * While not EOF { * lock DM lock * read from disk to inbuf, one block at a time * unlock DM lock * } * 2. MM thread: Move data from inbuf to outbuf * While something is in inbuf { * lock both DM and MS locks * copy from inbuf to outbuf, one block at a time * unlock DM and MS locks * } * 3. MS thread: Writes from memory buffer (outbuf) to screen * While something is in outbuf { * lock MS lock * write to screen, one block at a time * unlock MS lock * } . . . pluto% num ptcond.c 1 /* ptcond.c 2 * This program shows thread synchronization using a condition variable 3 * Two threads & one buffer: 4 * 1. Reader thread: Reads from disk to memory buffer 5 * while not EOF { 6 * lock mutex lock 7 * read from disk to inbuf, one block at a time 8 * if EOF 9 * set EOF flag 10 * else 11 * notify Writer via condition variable 12 * unlock mutex lock 13 * give up CPU 14 * } 15 * 2. Writer thread: Writes from memory to screen 16 * loop { 17 * lock mutex lock 18 * if (buffer is empty) 19 * if EOF 20 * break out of loop 21 * else 22 * sleep on condition variable 23 * else 24 * write to screen, one block at a time 25 * unlock mutex lock 26 * give up CPU 27 * } 28 * unlock mutex lock 29 * To compile: gcc ptcond.c -lpthread 30 * Sam Hsu (11/12/10) 31 */ 32 #define _REENTRANT 33 #include 34 #include 35 #include 36 #include 37 #include 38 typedef struct { 39 char buf[BUFSIZ]; 40 int size; 41 } BUFFER; 42 enum {FALSE = 0, TRUE = 1}; 43 pthread_mutex_t mutexlock = PTHREAD_MUTEX_INITIALIZER; 44 pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; 45 int fdes, EOFflag = FALSE; 46 BUFFER data = {"", 0}; 47 main(int argc, char *argv[]) 48 { 49 int status, *status_ptr = &status; 50 pthread_t rthread, wthread; 51 void *Rthread(void *), *Wthread(void *); 52 if ((fdes = open(argv[1], O_RDONLY)) == -1) { 53 fprintf(stderr, "failed to open %s\n", argv[1]); 54 exit(1); 55 } 56 if (pthread_create(&rthread, NULL, Rthread, (void *)NULL) != 0) { 57 fprintf(stderr, "failed to create Reader thread\n"); 58 exit(2); 59 } 60 if (pthread_create(&wthread, NULL, Wthread, (void *)NULL) != 0) { 61 fprintf(stderr, "failed to create Writer thread\n"); 62 exit(3); 63 } 64 if (pthread_join(rthread, (void **)status_ptr) != 0) { 65 fprintf(stderr, "failed to terminate Reader thread\n"); 66 exit(4); 67 } 68 if (pthread_join(wthread, (void **)status_ptr) != 0) { 69 fprintf(stderr, "failed to terminate Writer thread\n"); 70 exit(5); 71 } 72 pthread_mutex_destroy(&mutexlock); /* assume no error */ 73 pthread_cond_destroy(&condvar); 74 close(fdes); 75 return(0); 76 } /* main */ 77 void *Rthread(void *dummy) /* Reader thread */ 78 { 79 int err; 80 while (EOFflag != TRUE) { 81 if ((err = pthread_mutex_lock(&mutexlock)) != 0) { 82 fprintf(stderr, "mutex lock failed %d\n", err); 83 pthread_exit((void *)6); 84 } 85 if (data.size == 0) { /* buffer is empty */ 86 if (data.size = read(fdes, data.buf, BUFSIZ)) /* assume OK */ 87 pthread_cond_signal(&condvar); /* wake up Writer */ 88 else /* EOF */ 89 EOFflag = TRUE; 90 } 91 pthread_mutex_unlock(&mutexlock); /* assume no error */ 92 sched_yield(); /* relinquish CPU */ 93 } 94 return (void *)NULL; 95 } /* Rthread */ 96 void *Wthread(void *dummy) /* Writer thread */ 97 { 98 int err; 99 while (TRUE) { 100 if ((err = pthread_mutex_lock(&mutexlock)) != 0) { 101 fprintf(stderr, "mutex lock failed %d\n", err); 102 pthread_exit((void *)7); 103 } 104 if (data.size == 0) { /* buffer is empty */ 105 if (EOFflag == TRUE) /* no more input */ 106 break; 107 pthread_cond_wait(&condvar, &mutexlock); /* sleep on condvar */ 108 } else { /* something in buffer */ 109 write(STDOUT_FILENO, data.buf, data.size); 110 data.size = 0; /* empty buffer */ 111 pthread_mutex_unlock(&mutexlock); /* assume no error */ 112 sched_yield(); /* relinquish CPU */ 113 } 114 } 115 pthread_mutex_unlock(&mutexlock); /* assume no error */ 116 return (void *)NULL; 117 } /* Wthread */ pluto% ptcond ptcond.c /* ptcond.c * This program shows thread synchronization using a condition variable * Two threads & one buffer: * 1. Reader thread: Reads from disk to memory buffer * while not EOF { * lock mutex lock * read from disk to inbuf, one block at a time * if EOF * set EOF flag * else * notify Writer via condition variable * unlock mutex lock * give up CPU * } * 2. Writer thread: Writes from memory to screen * loop { * lock mutex lock * if (buffer is empty) * if EOF * break out of loop * else * sleep on condition variable * else * write to screen, one block at a time * unlock mutex lock * give up CPU * } * unlock mutex lock ... pluto% num ptsd.c 1 /* ptsd.c 2 This program shows how to manipulate thread specific data. 3 A data structure is locally created in main(), but is stored in a global 4 area using pthread_setspecific() with a TSD key. 5 Once stored, the TSD data can be accessed (R/W) by all functions in the 6 thread using pthread_getspecific() with the associated key. 7 In order to protect the globally sharable TSD data, a mutex is used to 8 ensure synchronized approaches. 9 Note: a TSD key is created with a destructor function specified at the 10 same time; however, the current implementations of TSD require the 11 destructor be invoked explicitly. 12 To compile: gcc ptsd.c -lpthread 13 Sam Hsu (11/19/10) 14 */ 15 #define _POSIX_C_SOURCE 199506L 16 #include 17 #include 18 #include 19 #include 20 typedef struct tsd_t { /* a global data struct known to all */ 21 char *data_1; 22 char *data_2; 23 } TSD; 24 static pthread_mutex_t tsdlock; /* to ensure mutual exclusion */ 25 main() 26 { 27 int err, friend(pthread_key_t); 28 pthread_key_t key; 29 void *tsd, cleanup(void *); 30 char *msg = "Greetings from main()"; 31 TSD tsdbuf = {(char *)NULL, (char *)NULL}; 32 /* to create a TSD key */ 33 if ((err = pthread_key_create(&key, cleanup)) != 0) { 34 fprintf(stderr, "Unable to create a TSD key\n"); 35 exit(1); 36 } 37 /* to initialize a TSD lock */ 38 if ((err=pthread_mutex_init(&tsdlock, (pthread_mutexattr_t *)NULL)) != 0) { 39 fprintf(stderr, "Unable to init a TSD lock\n"); 40 exit(2); 41 } 42 /* to allocate space and copy data to TSD structure */ 43 tsdbuf.data_1 = (char *)malloc((size_t)strlen(msg)); 44 strcpy(tsdbuf.data_1, msg); 45 /* to store the TSD values globally */ 46 tsd = (void *)&tsdbuf; 47 if (pthread_setspecific(key, tsd) != 0) { 48 fprintf(stderr, "Unable to do setspecific"); 49 exit(3); 50 } 51 if ((err = friend(key)) != 0) /* a call to share TSD data */ 52 return(err); 53 printf("%s\n", tsdbuf.data_1); /* to display TSD data */ 54 printf("%s\n", tsdbuf.data_2); 55 pthread_key_delete(key); /* assume no error */ 56 cleanup(tsd); /* needs to be called explicitly */ 57 pthread_mutex_destroy(&tsdlock); 58 return(0); 59 } /* main */ 60 int friend(pthread_key_t key) 61 { 62 char *msg = "Best wishes from friend()"; 63 TSD *tsd; 64 if (pthread_mutex_lock(&tsdlock) != 0) { 65 fprintf(stderr, "Unable to lock tsdlock\n"); 66 return(1); 67 } 68 tsd = (TSD *)pthread_getspecific(key); 69 tsd->data_2 = (char *)malloc((size_t)strlen(msg)); 70 strcpy(tsd->data_2, msg); 71 if (pthread_mutex_unlock(&tsdlock) != 0) { 72 fprintf(stderr, "Unable to unlock tsdlock\n"); 73 return(2); 74 } 75 return(0); 76 } /* friend */ 77 void cleanup(void *val) /* destructor function */ 78 { 79 free(((TSD *)val)->data_1); 80 free(((TSD *)val)->data_2); 81 } /* cleanup */ pluto% num ptsd.c Greetings from main() Best wishes from friend() pluto% num ptsig.c 1 /* ptsig.c 2 This program illustrates the use of signals in threads. 3 Three threads including the main thread. 4 main thread 5 a. Set up a signal mask to block all signals. 6 b. Set up signal handlers for SIGINT and SIGUSR1. 7 c. Create thread_1, detached. 8 d. Create thread_2, nondetached. 9 e. Send SIGINT & SIGUSR1 to thread_1. 10 f. Quit. 11 thread_1 12 a. Unblock all to embrace all signals. 13 b. Wait for signals. 14 c. Send SIGINT and SIGUSR1 to thread_2 15 d. Wait for thread_2 to terminate 16 e. Print thread_2 return status. 17 f. Quit 18 thread_2 19 a. Unblock SIGUSR1 -- all others blocked due to inheritance. 20 b. Wait for signals. 21 c. Quit 22 Note: There is hardly any error checking in this example -- not a good 23 idea, but to make the program a bit more easier to explain. 24 To compile: gcc ptsig.c -lpthread 25 Sam Hsu (11/19/10) 26 */ 27 #define _POSIX_C_SOURCE 199506L 28 #include 29 #include 30 #include 31 pthread_t tid2; 32 void int_handler(), usr1_handler(); 33 main() 34 { 35 pthread_t tid1; 36 pthread_attr_t attr_obj; /* a thread attribute variable */ 37 void *thread_1(void *), *thread_2(void *); 38 sigset_t sigmask; 39 struct sigaction action; 40 /* set up signal mask to block all in main thread */ 41 sigfillset(&sigmask); /* to turn on all bits */ 42 pthread_sigmask(SIG_BLOCK, &sigmask, (sigset_t *)0); 43 /* set up signal handlers for SIGINT & SIGUSR1 */ 44 action.sa_flags = 0; 45 action.sa_handler = int_handler; 46 sigaction(SIGINT, &action, (struct sigaction *)0); 47 action.sa_handler = usr1_handler; 48 sigaction(SIGUSR1, &action, (struct sigaction *)0); 49 pthread_attr_init(&attr_obj); /* init it to default */ 50 pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_DETACHED); 51 pthread_create(&tid1, &attr_obj, thread_1, (void *)NULL); 52 printf("TID(%u) created\n", tid1); 53 pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_JOINABLE); 54 pthread_create(&tid2, &attr_obj, thread_2, (void *)NULL); 55 printf("TID(%u) created\n", tid2); 56 sleep(1); /* for some reason a sleep is needed here */ 57 printf("main(%u) sending SIGINT to TID(%u)\n", pthread_self(), tid1); 58 pthread_kill(tid1, SIGINT); /* not blocked by tid1 */ 59 printf("main(%u) sending SIGUSR1 to TID(%u)\n", pthread_self(), tid1); 60 pthread_kill(tid1, SIGUSR1); /* not blocked by tid1 */ 61 printf("main(%u) is terminating\n", pthread_self()); 62 pthread_exit((void *)NULL); /* will not terminate process */ 63 } /* main */ 64 void *thread_1(void *dummy) 65 { 66 int sig, status, *status_ptr = &status; 67 sigset_t sigmask; 68 sigfillset(&sigmask); /* will unblock all signals */ 69 pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0); 70 sigwait(&sigmask, &sig); 71 switch(sig) { 72 case SIGINT: 73 int_handler(sig); 74 break; 75 default: 76 break; 77 } 78 printf("TID(%u) sending SIGINT to %u\n", pthread_self(), tid2); 79 pthread_kill(tid2, SIGINT); /* blocked by tid2 */ 80 printf("TID(%u) sending SIGUSR1 to %u\n", pthread_self(), tid2); 81 pthread_kill(tid2, SIGUSR1); /* not blocked by tid2 */ 82 pthread_join(tid2, (void **)status_ptr); 83 printf("TID(%u) exit status = %d\n", tid2, status); 84 printf("TID(%u) is terminating\n", pthread_self()); 85 pthread_exit((void *)NULL); /* calling thread will terminate */ 86 } /* thread_1 */ 87 void *thread_2(void *dummy) 88 { 89 int sig; 90 sigset_t sigmask; 91 sigemptyset(&sigmask); /* to zero out all bits */ 92 sigaddset(&sigmask, SIGUSR1); /* to unblock SIGUSR1 */ 93 pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0); 94 sigwait(&sigmask, &sig); 95 switch(sig) { 96 case SIGUSR1: 97 usr1_handler(sig); 98 break; 99 default: 100 break; 101 } 102 printf("TID(%u) is terminating\n", pthread_self()); 103 pthread_exit((void *)NULL); /* calling thread will terminate */ 104 } /* thread_2 */ 105 void int_handler(int dummy) 106 { 107 printf("SIGINT received by TID(%u)\n", pthread_self()); 108 } /* int_handler */ 109 void usr1_handler(int dummy) 110 { 111 printf("SIGUSR1 received by TID(%u)\n", pthread_self()); 112 } /* usr1_handler */ pluto% ptsig TID(3087625104) created TID(3077135248) created main(3087627968) sending SIGINT to TID(3087625104) SIGINT received by TID(3087625104) TID(3087625104) sending SIGINT to 3077135248 TID(3087625104) sending SIGUSR1 to 3077135248 SIGUSR1 received by TID(3077135248) TID(3077135248) is terminating TID(3077135248) exit status = 0 TID(3087625104) is terminating main(3087627968) sending SIGUSR1 to TID(3087625104) main(3087627968) is terminating