ex3.c 4.3 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 */
B
bernard.xiong@gmail.com 已提交
9 10 11
/* Multi-thread searching.
   Illustrates: thread cancellation, cleanup handlers. */

12
#include <sys/errno.h>
B
bernard.xiong@gmail.com 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#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);
}