Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
glibc/linuxthreads/Examples/ex3.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
152 lines (117 sloc)
4.1 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Multi-thread searching. | |
Illustrates: thread cancellation, cleanup handlers. */ | |
#include <errno.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <sys/types.h> | |
#include <pthread.h> | |
/* Defines the number of searching threads */ | |
#define NUM_THREADS 5 | |
/* Function prototypes */ | |
void *search(void *); | |
void print_it(void *); | |
/* Global variables */ | |
pthread_t threads[NUM_THREADS]; | |
pthread_mutex_t lock; | |
int tries; | |
volatile int started; | |
int main(int argc, char ** argv) | |
{ | |
int i; | |
int pid; | |
/* create a number to search for */ | |
pid = getpid(); | |
printf("Searching for the number = %d...\n", pid); | |
/* Initialize the mutex lock */ | |
pthread_mutex_init(&lock, NULL); | |
/* Create the searching threads */ | |
for (started=0; started<NUM_THREADS; started++) | |
pthread_create(&threads[started], NULL, search, (void *) (long int) pid); | |
/* Wait for (join) all the searching threads */ | |
for (i=0; i<NUM_THREADS; i++) | |
pthread_join(threads[i], NULL); | |
printf("It took %d tries to find the number.\n", tries); | |
/* Exit the program */ | |
return 0; | |
} | |
/* This is the cleanup function that is called | |
when the threads are cancelled */ | |
void print_it(void *arg) | |
{ | |
int *try = (int *) arg; | |
pthread_t tid; | |
/* Get the calling thread's ID */ | |
tid = pthread_self(); | |
/* Print where the thread was in its search when it was cancelled */ | |
printf("Thread %lx was canceled on its %d try.\n", tid, *try); | |
} | |
/* This is the search routine that is executed in each thread */ | |
void *search(void *arg) | |
{ | |
int num = (long int) arg; | |
int i, j, ntries; | |
pthread_t tid; | |
/* get the calling thread ID */ | |
tid = pthread_self(); | |
/* use the thread ID to set the seed for the random number generator */ | |
/* Since srand and rand are not thread-safe, serialize with lock */ | |
/* Try to lock the mutex lock -- | |
if locked, check to see if the thread has been cancelled | |
if not locked then continue */ | |
while (pthread_mutex_trylock(&lock) == EBUSY) | |
pthread_testcancel(); | |
srand((int)tid); | |
i = rand() & 0xFFFFFF; | |
pthread_mutex_unlock(&lock); | |
ntries = 0; | |
/* Set the cancellation parameters -- | |
- Enable thread cancellation | |
- Defer the action of the cancellation */ | |
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | |
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); | |
while (started < NUM_THREADS) | |
sched_yield (); | |
/* Push the cleanup routine (print_it) onto the thread | |
cleanup stack. This routine will be called when the | |
thread is cancelled. Also note that the pthread_cleanup_push | |
call must have a matching pthread_cleanup_pop call. The | |
push and pop calls MUST be at the same lexical level | |
within the code */ | |
/* Pass address of `ntries' since the current value of `ntries' is not | |
the one we want to use in the cleanup function */ | |
pthread_cleanup_push(print_it, (void *)&ntries); | |
/* Loop forever */ | |
while (1) { | |
i = (i + 1) & 0xFFFFFF; | |
ntries++; | |
/* Does the random number match the target number? */ | |
if (num == i) { | |
/* Try to lock the mutex lock -- | |
if locked, check to see if the thread has been cancelled | |
if not locked then continue */ | |
while (pthread_mutex_trylock(&lock) == EBUSY) | |
pthread_testcancel(); | |
/* Set the global variable for the number of tries */ | |
tries = ntries; | |
printf("Thread %lx found the number!\n", tid); | |
/* Cancel all the other threads */ | |
for (j=0; j<NUM_THREADS; j++) | |
if (threads[j] != tid) pthread_cancel(threads[j]); | |
/* Break out of the while loop */ | |
break; | |
} | |
/* Every 100 tries check to see if the thread has been cancelled. */ | |
if (ntries % 100 == 0) { | |
pthread_testcancel(); | |
} | |
} | |
/* The only way we can get here is when the thread breaks out | |
of the while loop. In this case the thread that makes it here | |
has found the number we are looking for and does not need to run | |
the thread cleanup function. This is why the pthread_cleanup_pop | |
function is called with a 0 argument; this will pop the cleanup | |
function off the stack without executing it */ | |
pthread_cleanup_pop(0); | |
return((void *)0); | |
} |