155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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 libc_ex3()
 | 
						|
{
 | 
						|
  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 *)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;
 | 
						|
}
 | 
						|
#include <finsh.h>
 | 
						|
FINSH_FUNCTION_EXPORT(libc_ex3, example 5 for libc);
 | 
						|
 | 
						|
/* 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 = (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);
 | 
						|
}
 |