reality% 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 */ 19 #define _REENTRANT 20 #include 21 #include 22 #define MAX 10 23 int main(int argc, char *argv[]) 24 { 25 int i, status, *status_ptr = &status; 26 pthread_t thread[MAX]; 27 void *prt_arg(void *); 28 for (i = 0; i < argc-1; i++) { /* creating threads */ 29 if (pthread_create(&thread[i], NULL, prt_arg, (void *)argv[i+1]) != 0) { 30 fprintf(stderr, "Failed to create a thread\n"); 31 exit(1); 32 } 33 } 34 for (i = 0; i < argc-1; i++) { /* waiting for thread terminations */ 35 if (pthread_join(thread[i], (void **)status_ptr) != 0) { 36 fprintf(stderr, "Failed to terminate a thread\n"); 37 exit(2); 38 } 39 printf("Thread %d returns %d\n", thread[i], status); 40 } 41 return(0); 42 } 43 void *prt_arg(void *arg) 44 { 45 pthread_t tid = pthread_self(); /* to get tid for itself */ 46 printf("Thread %d got %s\n", tid, (char *)arg); 47 return (void *)NULL; 48 } reality% pthread A thread example Thread 4 got A Thread 5 got thread Thread 6 got example Thread 4 returns 0 Thread 5 returns 0 Thread 6 returns 0 reality% 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 -lthread 23 */ 24 #define _REENTRANT 25 #include 26 #include 27 #include 28 #include 29 #include 30 enum {FALSE = 0, TRUE = 1}; 31 pthread_mutex_t DMlock = PTHREAD_MUTEX_INITIALIZER, 32 MMlock = PTHREAD_MUTEX_INITIALIZER, 33 MSlock = PTHREAD_MUTEX_INITIALIZER; 34 int fdes, nread = 1, inflag = FALSE, outflag = FALSE; 35 char inbuf[BUFSIZ], outbuf[BUFSIZ]; 36 main(int argc, char *argv[]) 37 { 38 int status, *status_ptr = &status; 39 pthread_t dmthread, mmthread, msthread; 40 void *DMthread(void *), *MMthread(void *), *MSthread(void *); 41 if ((fdes = open(argv[1], O_RDONLY)) == -1) { 42 fprintf(stderr, "failed to open %s\n", argv[1]); 43 exit(1); 44 } 45 if (pthread_create(&dmthread, NULL, DMthread, (void *)NULL) != 0) { 46 fprintf(stderr, "failed to create DMthread\n"); 47 exit(2); 48 } 49 if (pthread_create(&mmthread, NULL, MMthread, (void *)NULL) != 0) { 50 fprintf(stderr, "failed to create MMthread\n"); 51 exit(3); 52 } 53 if (pthread_create(&msthread, NULL, MSthread, (void *)NULL) != 0) { 54 fprintf(stderr, "failed to create MSthread\n"); 55 exit(4); 56 } 57 if (pthread_join(dmthread, (void **)status_ptr) != 0) { 58 fprintf(stderr, "failed to terminate DMthread\n"); 59 exit(5); 60 } 61 if (pthread_join(mmthread, (void **)status_ptr) != 0) { 62 fprintf(stderr, "failed to terminate MMthread\n"); 63 exit(6); 64 } 65 if (pthread_join(msthread, (void **)status_ptr) != 0) { 66 fprintf(stderr, "failed to terminate MSthread\n"); 67 exit(7); 68 } 69 pthread_mutex_destroy(&DMlock); /* assume no error */ 70 pthread_mutex_destroy(&MMlock); 71 pthread_mutex_destroy(&MSlock); 72 close(fdes); 73 return(0); 74 } /* main */ 75 void *DMthread(void *dummy) 76 { 77 int err; 78 while (nread) { 79 while (inflag == TRUE) { /* inbuf data not copied out yet */ 80 thr_yield(); /* give up CPU -- not POSIX */ 81 } 82 if ((err = pthread_mutex_lock(&DMlock)) != 0) { 83 fprintf(stderr, "DMthread lock failed %d\n", err); 84 pthread_exit((void *)8); 85 } 86 if ((nread = read(fdes, inbuf, BUFSIZ)) > 0) /* assume no error */ 87 inflag = TRUE; /* new data in inbuf */ 88 if ((err = pthread_mutex_unlock(&DMlock)) != 0) { 89 fprintf(stderr, "DMthread unlock failed %d\n", err); 90 pthread_exit((void *)9); 91 } 92 } 93 pthread_exit((void *)NULL); 94 } /* DMthread */ 95 void *MMthread(void *dummy) 96 { 97 int err; 98 while (nread != 0 || inflag == TRUE) { /* something in inbuf */ 99 if (outflag == TRUE) { /* outbuf data not processed yet */ 100 thr_yield(); /* let other threads go first */ 101 continue; /* in case it is the last block */ 102 } 103 if ((err = pthread_mutex_lock(&DMlock)) != 0) { 104 fprintf(stderr, "MMthread lock failed %d\n", err); 105 pthread_exit((void *)10); 106 } 107 if ((err = pthread_mutex_lock(&MSlock)) != 0) { 108 fprintf(stderr, "MMthread lock failed %d\n", err); 109 pthread_exit((void *)11); 110 } 111 memcpy(outbuf, inbuf, nread); /* copy inbuf to outbuf, assume OK */ 112 outflag = TRUE; /* indicate new data in outbuf */ 113 inflag = FALSE; /* indicate data in inbuf copied */ 114 if ((err = pthread_mutex_unlock(&DMlock)) != 0) { 115 fprintf(stderr, "MMthread unlock failed %d\n", err); 116 pthread_exit((void *)12); 117 } 118 if ((err = pthread_mutex_unlock(&MSlock)) != 0) { 119 fprintf(stderr, "MMthread unlock failed %d\n", err); 120 pthread_exit((void *)13); 121 } 122 } 123 pthread_exit((void *)NULL); 124 } /* MMthread */ 125 void *MSthread(void *dummy) 126 { 127 int err; 128 while (nread != 0 || outflag == TRUE || inflag == TRUE) { 129 if (outflag == FALSE) { 130 thr_yield(); /* let others go first */ 131 continue; 132 } 133 if ((err = pthread_mutex_lock(&MSlock)) != 0) { 134 fprintf(stderr, "MSthread lock failed %d\n", err); 135 pthread_exit((void *)14); 136 } 137 write(STDOUT_FILENO, outbuf, nread); /* assume no error */ 138 outflag = FALSE; /* outbuf emptied */ 139 if ((err = pthread_mutex_unlock(&MSlock)) != 0) { 140 fprintf(stderr, "MSthread unlock failed %d\n", err); 141 pthread_exit((void *)15); 142 } 143 } 144 pthread_exit((void *)NULL); 145 } /* MSthread */ reality% 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 } .... reality% 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 -lthread 30 */ 31 #define _REENTRANT 32 #include 33 #include 34 #include 35 #include 36 #include 37 typedef struct { 38 char buf[BUFSIZ]; 39 int size; 40 } BUFFER; 41 enum {FALSE = 0, TRUE = 1}; 42 pthread_mutex_t mutexlock = PTHREAD_MUTEX_INITIALIZER; 43 pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; 44 int fdes, EOFflag = FALSE; 45 BUFFER data = {"", 0}; 46 main(int argc, char *argv[]) 47 { 48 int status, *status_ptr = &status; 49 pthread_t rthread, wthread; 50 void *Rthread(void *), *Wthread(void *); 51 if ((fdes = open(argv[1], O_RDONLY)) == -1) { 52 fprintf(stderr, "failed to open %s\n", argv[1]); 53 exit(1); 54 } 55 if (pthread_create(&rthread, NULL, Rthread, (void *)NULL) != 0) { 56 fprintf(stderr, "failed to create Reader thread\n"); 57 exit(2); 58 } 59 if (pthread_create(&wthread, NULL, Wthread, (void *)NULL) != 0) { 60 fprintf(stderr, "failed to create Writer thread\n"); 61 exit(3); 62 } 63 if (pthread_join(rthread, (void **)status_ptr) != 0) { 64 fprintf(stderr, "failed to terminate Reader thread\n"); 65 exit(4); 66 } 67 if (pthread_join(wthread, (void **)status_ptr) != 0) { 68 fprintf(stderr, "failed to terminate Writer thread\n"); 69 exit(5); 70 } 71 pthread_mutex_destroy(&mutexlock); /* assume no error */ 72 pthread_cond_destroy(&condvar); 73 close(fdes); 74 return(0); 75 } /* main */ 76 void *Rthread(void *dummy) /* Reader thread */ 77 { 78 int err; 79 while (EOFflag != TRUE) { 80 if ((err = pthread_mutex_lock(&mutexlock)) != 0) { 81 fprintf(stderr, "mutex lock failed %d\n", err); 82 pthread_exit((void *)6); 83 } 84 if (data.size == 0) { /* buffer is empty */ 85 if (data.size = read(fdes, data.buf, BUFSIZ)) /* assume OK */ 86 pthread_cond_signal(&condvar); /* wake up Writer */ 87 else /* EOF */ 88 EOFflag = TRUE; 89 } 90 pthread_mutex_unlock(&mutexlock); /* assume no error */ 91 thr_yield(); /* relinquish CPU -- not POSIX */ 92 } 93 return (void *)NULL; 94 } /* Rthread */ 95 void *Wthread(void *dummy) /* Writer thread */ 96 { 97 int err; 98 while (TRUE) { 99 if ((err = pthread_mutex_lock(&mutexlock)) != 0) { 100 fprintf(stderr, "mutex lock failed %d\n", err); 101 pthread_exit((void *)7); 102 } 103 if (data.size == 0) { /* buffer is empty */ 104 if (EOFflag == TRUE) /* no more input */ 105 break; 106 pthread_cond_wait(&condvar, &mutexlock); /* sleep on condvar */ 107 } else { /* something in buffer */ 108 write(STDOUT_FILENO, data.buf, data.size); 109 data.size = 0; /* empty buffer */ 110 pthread_mutex_unlock(&mutexlock); /* assume no error */ 111 thr_yield(); /* relinquish CPU */ 112 } 113 } 114 pthread_mutex_unlock(&mutexlock); /* assume no error */ 115 return (void *)NULL; 116 } /* Wthread */ reality% ptcond /* 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 ... reality% 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 */ 14 #define _POSIX_C_SOURCE 199506L 15 #include 16 #include 17 typedef struct tsd_t { /* a global data struct known to all */ 18 char *data_1; 19 char *data_2; 20 } TSD; 21 static pthread_mutex_t tsdlock; /* to ensure mutual exclusion */ 22 main() 23 { 24 int err, friend(pthread_key_t); 25 pthread_key_t key; 26 void *tsd, cleanup(void *); 27 char *msg = "Greetings from main()"; 28 TSD tsdbuf = {(char *)NULL, (char *)NULL}; 29 /* to create a TSD key */ 30 if ((err = pthread_key_create(&key, cleanup)) != 0) { 31 fprintf(stderr, "Unable to create a TSD key\n"); 32 exit(1); 33 } 34 /* to initialize a TSD lock */ 35 if ((err=pthread_mutex_init(&tsdlock, (pthread_mutexattr_t *)NULL)) != 0) { 36 fprintf(stderr, "Unable to init a TSD lock\n"); 37 exit(2); 38 } 39 /* to allocate space and copy data to TSD structure */ 40 tsdbuf.data_1 = (char *)malloc((size_t)strlen(msg)); 41 strcpy(tsdbuf.data_1, msg); 42 /* to store the TSD values globally */ 43 tsd = (void *)&tsdbuf; 44 if (pthread_setspecific(key, tsd) != 0) { 45 fprintf(stderr, "Unable to do setspecific"); 46 exit(3); 47 } 48 if ((err = friend(key)) != 0) /* a call to share TSD data */ 49 return(err); 50 printf("%s\n", tsdbuf.data_1); /* to display TSD data */ 51 printf("%s\n", tsdbuf.data_2); 52 pthread_key_delete(key); /* assume no error */ 53 cleanup(tsd); /* needs to be called explicitly */ 54 pthread_mutex_destroy(&tsdlock); 55 return(0); 56 } /* main */ 57 int friend(pthread_key_t key) 58 { 59 char *msg = "Best wishes from friend()"; 60 TSD *tsd; 61 if (pthread_mutex_lock(&tsdlock) != 0) { 62 fprintf(stderr, "Unable to lock tsdlock\n"); 63 return(1); 64 } 65 tsd = (TSD *)pthread_getspecific(key); 66 tsd->data_2 = (char *)malloc((size_t)strlen(msg)); 67 strcpy(tsd->data_2, msg); 68 if (pthread_mutex_unlock(&tsdlock) != 0) { 69 fprintf(stderr, "Unable to unlock tsdlock\n"); 70 return(2); 71 } 72 return(0); 73 } /* friend */ 74 void cleanup(void *val) /* destructor function */ 75 { 76 free(((TSD *)val)->data_1); 77 free(((TSD *)val)->data_2); 78 } /* cleanup */ reality% ptsd Greetings from main() Best wishes from friend() reality% 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 */ 26 #define _POSIX_C_SOURCE 199506L 27 #include 28 #include 29 #include 30 pthread_t tid2; 31 void int_handler(), usr1_handler(); 32 main() 33 { 34 pthread_t tid1; 35 pthread_attr_t attr_obj; /* a thread attribute variable */ 36 void *thread_1(void *), *thread_2(void *); 37 sigset_t sigmask; 38 struct sigaction action; 39 /* set up signal mask to block all in main thread */ 40 sigfillset(&sigmask); /* to turn on all bits */ 41 pthread_sigmask(SIG_BLOCK, &sigmask, (sigset_t *)0); 42 /* set up signal handlers for SIGINT & SIGUSR1 */ 43 action.sa_flags = 0; 44 action.sa_handler = int_handler; 45 sigaction(SIGINT, &action, (struct sigaction *)0); 46 action.sa_handler = usr1_handler; 47 sigaction(SIGUSR1, &action, (struct sigaction *)0); 48 pthread_attr_init(&attr_obj); /* init it to default */ 49 pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_DETACHED); 50 pthread_create(&tid1, &attr_obj, thread_1, (void *)NULL); 51 printf("TID(%d) created\n", tid1); 52 pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_JOINABLE); 53 pthread_create(&tid2, &attr_obj, thread_2, (void *)NULL); 54 printf("TID(%d) created\n", tid2); 55 sleep(1); /* for some reason a sleep is needed here */ 56 printf("main(%d) sending SIGINT to TID(%d)\n", pthread_self(), tid1); 57 pthread_kill(tid1, SIGINT); /* not blocked by tid1 */ 58 printf("main(%d) sending SIGUSR1 to TID(%d)\n", pthread_self(), tid1); 59 pthread_kill(tid1, SIGUSR1); /* not blocked by tid1 */ 60 printf("main(%d) is terminating\n", pthread_self()); 61 pthread_exit((void *)NULL); /* will not terminate process */ 62 } /* main */ 63 void *thread_1(void *dummy) 64 { 65 int sig, status, *status_ptr = &status; 66 sigset_t sigmask; 67 sigfillset(&sigmask); /* will unblock all signals */ 68 pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0); 69 sigwait(&sigmask, &sig); 70 switch(sig) { 71 case SIGINT: 72 int_handler(sig); 73 break; 74 default: 75 break; 76 } 77 printf("TID(%d) sending SIGINT to %d\n", pthread_self(), tid2); 78 pthread_kill(tid2, SIGINT); /* blocked by tid2 */ 79 printf("TID(%d) sending SIGUSR1 to %d\n", pthread_self(), tid2); 80 pthread_kill(tid2, SIGUSR1); /* not blocked by tid2 */ 81 pthread_join(tid2, (void **)status_ptr); 82 printf("TID(%d) exit status = %d\n", tid2, status); 83 printf("TID(%d) is terminating\n", pthread_self()); 84 pthread_exit((void *)NULL); /* calling thread will terminate */ 85 } /* thread_1 */ 86 void *thread_2(void *dummy) 87 { 88 int sig; 89 sigset_t sigmask; 90 sigemptyset(&sigmask); /* to zero out all bits */ 91 sigaddset(&sigmask, SIGUSR1); /* to unblock SIGUSR1 */ 92 pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0); 93 sigwait(&sigmask, &sig); 94 switch(sig) { 95 case SIGUSR1: 96 usr1_handler(sig); 97 break; 98 default: 99 break; 100 } 101 printf("TID(%d) is terminating\n", pthread_self()); 102 pthread_exit((void *)NULL); /* calling thread will terminate */ 103 } /* thread_2 */ 104 void int_handler(int dummy) 105 { 106 printf("SIGINT received by TID(%d)\n", pthread_self()); 107 } /* int_handler */ 108 void usr1_handler(int dummy) 109 { 110 printf("SIGUSR1 received by TID(%d)\n", pthread_self()); 111 } /* usr1_handler */ reality% ptsig TID(4) created TID(5) created main(1) sending SIGINT to TID(4) main(1) sending SIGUSR1 to TID(4) main(1) is terminating SIGUSR1 received by TID(4) SIGINT received by TID(4) TID(4) sending SIGINT to 5 TID(4) sending SIGUSR1 to 5 SIGUSR1 received by TID(5) TID(5) is terminating TID(5) exit status = 0 TID(4) is terminating