blob: 62047395b554b7a132016ff8feaa43129574a218 [file] [log] [blame]
/********************************************************
* 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 <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#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 %p\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 = 0; i < 10000000; i++) {
if (i%10000 == 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%10000 == 0)
print_count(messagep, *my_id, i);
if (i%100000 == 0) {
printf("\n%s\t%d Look, 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<NUM_THREADS; i++) {
pthread_cancel(threads[i]);
}
/* wait until all threads have finished */
for (i=0; i<NUM_THREADS; i++) {
pthread_join(threads[i], &statusp);
if (statusp == PTHREAD_CANCELED) {
printf("main(): joined to thread %d, statusp=PTHREAD_CANCELED\n",i);
} else {
printf("main(): joined to thread %d\n",i);
}
}
printf("main()\t\tall %d threads have finished. \n", NUM_THREADS);
return 0;
}