/*
 * simple synchronization example, version 1:
 *
 * unsynchronized access to a resource (here, standard output) can lead to
 * problems.
 *
 * command-line argument gives number of threads.
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>		/* has sleep() */
#include <pthread.h>		/* has pthread_ routines */

void * thread_fcn(void * thread_arg);

/* ---- main program ---- */

int main(int argc, char* argv[]) {

    int i;
    int num_threads = 0;
    int * threadIDs;
    pthread_t * threads;

    if (argc < 2) {
        fprintf(stderr, "usage:  %s numthreads\n", argv[0]);
        return EXIT_FAILURE;
    }
    num_threads = atoi(argv[1]);
    if (num_threads <= 0) {
        fprintf(stderr, "usage:  %s numthreads\n", argv[0]);
        return EXIT_FAILURE;
    }

    /* Set up IDs for threads (need a separate variable for each since they're
     *   shared among threads).
     */
    threadIDs = malloc(num_threads * sizeof(int));
    for (i = 0; i < num_threads; ++i)
        threadIDs[i] = i;

    /* Start num_threads new threads, each with different ID. */
    threads = malloc(num_threads * sizeof(pthread_t));
    for (i = 0; i < num_threads; ++i) 
        pthread_create(&threads[i], NULL, thread_fcn, (void *) &threadIDs[i]);

    /* Wait for all threads to complete. */
    for (i = 0; i < num_threads; ++i) 
        pthread_join(threads[i], NULL);

    /* Clean up and exit. */
    free(threadIDs);
    free(threads);
    return EXIT_SUCCESS;
}

/* ---- code to be executed by each thread ---- */

void * thread_fcn(void * thread_arg) {
    int myID = * (int *) thread_arg;

    fprintf(stdout, "hello, world, ");
    sleep(1);
    fprintf(stdout, "from thread %d\n", myID);

    pthread_exit((void* ) NULL);
}