ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/alpha-snapshots/pthreads.0.9.2.tgz#/pthreads-0.9.2/dcelib/prime.c

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(&current_mutex);
	check(status, "4:Mutex_lock bad status\n");
	current_num = current_num + 2;	/* Skip even numbers */
	numerator = current_num;
	status = pthread_mutex_unlock(&current_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(&current_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.