/******************************************************** * An example source module to accompany... * * "Using POSIX Threads: Programming with Pthreads" * by Brad nichols, Dick Buttlar, Jackie Farrell * O'Reilly & Associates, Inc. * ******************************************************** * cancel.c -- * * Demonstrates pthread cancellation. * */ #include #include "pthread.h" #define NUM_THREADS 3 #define MESSAGE_MAX_LEN 80 int count=NUM_THREADS; /* number of threads active */ pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; /* mutual exclusion for count */ pthread_cond_t init_done=PTHREAD_COND_INITIALIZER; /* signaled by each thread after completing initial- ization */ int id_arg[3] = {0,1,2}; /* * Cleanup routine: last_breath() */ void last_breath(char *messagep) { printf("\n\n%s last_breath() cleanup routine: free'ing 0x%x\n\n", messagep, messagep); free(messagep); } /* * print_count() */ void print_count(char *messagep, int id, int i) { int last_type,tmp_type; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type); switch(id) { case 0: printf("%s %4d\n", messagep, i); break; case 1: printf("%s \t%4d\n", messagep, i); break; case 2: printf("%s \t\t%4d\n", messagep, i); break; } pthread_setcanceltype(last_type, &tmp_type); } /* * bullet_proof() */ void *bullet_proof(void *id_p) { int i=0, last_state; int *my_id = id_p; char *messagep; messagep = (char *)malloc(MESSAGE_MAX_LEN); sprintf(messagep, "Bullet Proof, thread #%d: ", *my_id); printf("%s\tI'm Alive, setting general cancellation OFF\n", messagep); /* push last_breath() routine onto stack */ pthread_cleanup_push( (void *)last_breath, (void *)messagep ); /* We turn off general cancelability here ... */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &last_state); pthread_mutex_lock(&lock); { printf("\n%s signaling main that my init is done\n", messagep); count -= 1; /* signal to program that entering loop */ pthread_cond_signal(&init_done); pthread_mutex_unlock(&lock); } /* loop forever until picked off with a cancel */ for(;;i++) { if (i%1000 == 0) print_count(messagep, *my_id, i); if (i%100000 == 0) { printf("\n%s This is the thread that never ends... #%d\n", messagep, i); } } /* Never get this far */ /* This pop is required by the standard, every push must have a pop in the same lexical block. */ pthread_cleanup_pop(0); return(NULL); } /* * ask_for_it() */ void *ask_for_it(void *id_p) { int i=0, last_state, last_type; int *my_id = id_p; char *messagep; messagep = (char *)malloc(MESSAGE_MAX_LEN); sprintf(messagep, "Ask For It, thread #%d: ", *my_id); /* push last_breath() routine onto stack */ pthread_cleanup_push( (void *)last_breath, (void *)messagep); /* We can turn on general cancelability here. Disable async cancellation */ printf("%s\tI'm Alive, setting deferred cancellation ON\n", messagep); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_type); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state); pthread_mutex_lock(&lock); { printf("\n%s signaling main that my init is done\n", messagep); count -= 1; /* signal to program that entering loop */ pthread_cond_signal(&init_done); pthread_mutex_unlock(&lock); } /* loop forever until picked off with a cancel */ for(;;i++) { if (i%1000 == 0) print_count(messagep, *my_id, i); if (i%10000 == 0) { printf("\n%s\tLook, I'll tell you when you can cancel me.\n",messagep,i); } pthread_testcancel(); } /* never get this far */ /* This pop is required by the standard, every push must have a pop in the same lexical block. */ pthread_cleanup_pop(0); return(NULL); } /* * sitting_duck() */ void *sitting_duck(void *id_p) { int i=0, last_state, last_type, last_tmp; int *my_id = id_p; char *messagep; messagep = (char *)malloc(MESSAGE_MAX_LEN); sprintf(messagep, "Sitting Duck, thread #%d: ", *my_id); /* push last_breath() routine onto stack */ pthread_cleanup_push( (void *)last_breath, (void *)messagep); pthread_mutex_lock(&lock); { printf("\n%s signaling main that my init is done\n", messagep); count -= 1; /* signal to program that entering loop */ pthread_cond_signal(&init_done); pthread_mutex_unlock(&lock); } /* Now, we're safe to turn on async cancellability */ printf("%s\tI'm Alive, setting async cancellation ON\n", messagep); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_type); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_state); /* loop forever until picked off with a cancel */ for(;;i++) { if (i%1000 == 0) print_count(messagep, *my_id, i++); if (i%10000 == 0) { pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_tmp); printf("\n%s\tHum, nobody here but us chickens. %d\n", messagep,i); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &last_tmp); } } /* never get this far */ /* This pop is required by the standard, every push must have a pop in the same lexical block. */ pthread_cleanup_pop(0); return(NULL); } extern int main(void) { int i; void * statusp; pthread_t threads[NUM_THREADS]; /* spawn the threads */ pthread_create(&(threads[0]), NULL, ask_for_it, (void *) &(id_arg[0])); pthread_create(&(threads[1]), NULL, sitting_duck, (void *) &(id_arg[1])); pthread_create(&(threads[2]), NULL, bullet_proof, (void *) &(id_arg[2])); printf("main(): %d threads created\n", NUM_THREADS); pthread_mutex_lock(&lock); /* wait until all threads have entered loops */ while (count != 0) { pthread_cond_wait(&init_done, &lock); } pthread_mutex_unlock(&lock); printf("main(): all threads have signaled that ready\n"); /* cancel each thread */ for (i=0; i