This is prime.c in view mode; [Download] [Up]
/*
* DECthreads example program conducting a prime number search
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <utils.h>
/*
* Constants used by the example.
*/
#define workers 5 /* Threads to perform prime check */
#define request 200 /* Number of primes to find */
/*
* Macros
*/
#define check(status,string) if (status == -1) perror (string)
/*
* Global data
*/
pthread_mutex_t prime_list; /* Mutex for use in accessing the prime */
pthread_mutex_t current_mutex; /* Mutex associated with current number */
pthread_mutex_t cond_mutex; /* Mutex used for ensuring CV integrity */
pthread_cond_t cond_var; /* Condition variable for thread start */
int current_num = -1; /* Next number to be checked, start odd */
int thread_hold = 1; /* Number associated with condition state */
int count = 0; /* Count of prime numbers - index to primes */
int primes[request]; /* Store prime numbers - synchronize access */
pthread_t threads[workers]; /* Array of worker threads */
static void
unlock_cond(pthread_addr_t arg)
{
int status; /* Hold status from pthread calls */
status = pthread_mutex_unlock(&cond_mutex);
check(status, "3:Mutex_unlock bad status\n");
}
/*
* Worker thread routine.
*
* Worker threads start with this routine, which begins with a condition
* wait designed to synchronize the workers and the parent. Each worker
* thread then takes a turn taking a number for which it will determine
* whether or not it is prime.
*
*/
void
prime_search(pthread_addr_t arg)
{
int numerator; /* Used for determing primeness */
int denominator;/* Used for determing primeness */
int cut_off; /* Number being checked div 2 */
int notifiee; /* Used during a cancelation */
int prime; /* Flag used to indicate primeness */
int my_number; /* Worker thread identifier */
int status; /* Hold status from pthread calls */
int not_done = 1; /* Work loop predicate */
my_number = (int) arg;
/*
* Synchronize threads and the parent using a condition variable, of
* which the predicate (thread_hold) will be set by the parent.
*/
status = pthread_mutex_lock(&cond_mutex);
check(status, "1:Mutex_lock bad status\n");
pthread_cleanup_push(unlock_cond, NULL);
while (thread_hold)
{
status = pthread_cond_wait(&cond_var, &cond_mutex);
check(status, "2:Cond_wait bad status\n");
}
pthread_cleanup_pop(1);
/*
* Perform checks on ever larger integers until the requested
* number of primes is found.
*/
while (not_done)
{
/* Cancelation point */
pthread_testcancel();
/* Get next integer to be checked */
status = pthread_mutex_lock(¤t_mutex);
check(status, "4:Mutex_lock bad status\n");
current_num = current_num + 2; /* Skip even numbers */
numerator = current_num;
status = pthread_mutex_unlock(¤t_mutex);
check(status, "5:Mutex_unlock bad status\n");
/* Only need to divide in half of number to verify not prime */
cut_off = numerator / 2 + 1;
prime = 1;
/* Check for prime; exit if something evenly divides */
for (denominator = 2; ((denominator < cut_off) && (prime));
denominator++)
{
prime = numerator % denominator;
}
if (prime != 0)
{
/* Explicitly turn off all cancels */
pthread_setcancel(CANCEL_OFF);
/*
* Lock a mutex and add this prime number to the list. Also,
* if this fulfills the request, cancel all other threads.
*/
status = pthread_mutex_lock(&prime_list);
check(status, "6:Mutex_lock bad status\n");
if (count < request)
{
primes[count] = numerator;
count++;
}
else if (count == request)
{
not_done = 0;
count++;
for (notifiee = 0; notifiee < workers; notifiee++)
{
if (notifiee != my_number)
{
status = pthread_cancel(threads[notifiee]);
check(status, "12:Cancel bad status\n");
}
}
}
status = pthread_mutex_unlock(&prime_list);
check(status, "13:Mutex_unlock bad status\n");
/* Reenable cancels */
pthread_setcancel(CANCEL_ON);
}
pthread_testcancel();
}
pthread_exit((pthread_addr_t) my_number);
}
int
main(int argc, char *argv[])
{
int worker_num; /* Counter used when indexing workers */
void *exit_value; /* Individual worker's return status */
int list; /* Used to print list of found primes */
int status; /* Hold status from pthread calls */
int index1; /* Used in sorting prime numbers */
int index2; /* Used in sorting prime numbers */
int temp; /* Used in a swap; part of sort */
int not_done; /* Indicates swap made in sort */
/*
* Create mutexes
*/
status = pthread_mutex_init(&prime_list, pthread_mutexattr_default);
check(status, "7:Mutex_init bad status\n");
status = pthread_mutex_init(&cond_mutex, pthread_mutexattr_default);
check(status, "8:Mutex_init bad status\n");
status = pthread_mutex_init(¤t_mutex, pthread_mutexattr_default);
check(status, "9:Mutex_init bad status\n");
/*
* Create conditon variable
*/
status = pthread_cond_init(&cond_var, pthread_condattr_default);
check(status, "10:Cond_init bad status\n");
/*
* Create the worker threads.
*/
for (worker_num = 0; worker_num < workers; worker_num++)
{
status = pthread_create(
&threads[worker_num],
pthread_attr_default,
(thread_proc_t) prime_search,
(pthread_addr_t) worker_num);
check(status, "11:Pthread_create bad status\n");
}
/*
* Set the predicate thread_hold to zero, and broadcast on the
* condition variable that the worker threads may proceed.
*/
status = pthread_mutex_lock(&cond_mutex);
check(status, "12:Mutex_lock bad status\n");
thread_hold = 0;
status = pthread_cond_broadcast(&cond_var);
status = pthread_mutex_unlock(&cond_mutex);
check(status, "13:Mutex_unlock bad status\n");
/*
* Join each of the worker threads inorder to obtain their
* summation totals, and to ensure each has completed
* successfully.
*
* Mark thread storage free to be reclaimed upon termination by
* detaching it.
*/
for (worker_num = 0; worker_num < workers; worker_num++)
{
status = pthread_join(
threads[worker_num],
&exit_value);
check(status, "14:Pthread_join bad status\n");
if (exit_value == (pthread_addr_t) worker_num)
printf("Thread terminated normally\n");
/*
* Upon normal termination the exit_value is equivalent to
* worker_num.
*/
status = pthread_detach(&threads[worker_num]);
check(status, "15:Pthread_detach bad status\n");
}
/*
* Take the list of prime numbers found by the worker threads and
* sort them from lowest value to highest. The worker threads work
* concurrently; there is no guarantee that the prime numbers
* will be found in order. Therefore, a sort is performed.
*/
not_done = 1;
for (index1 = 1; ((index1 < request) && (not_done)); index1++)
{
for (index2 = 0; index2 < index1; index2++)
{
if (primes[index1] < primes[index2])
{
temp = primes[index2];
primes[index2] = primes[index1];
primes[index1] = temp;
not_done = 0;
}
}
}
/*
* Print out the list of prime numbers that the worker threads
* found.
*/
printf("The list of %d primes follows:\n", request);
printf("%d", primes[0]);
for (list = 1; list < request; list++)
{
printf(",\t%d", primes[list]);
}
printf("\n");
return (EXIT_SUCCESS);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.