#include <assert>
#include <fstream>
#include <iostream>
#include <strstream>

#include <vector>
#include <time.h>

using namespace std;

#define THREAD_NUM 10


pthread_mutex_t     current_mutex;
pthread_mutex_t     cond_mutex;
pthread_cond_t      cond_var;
int                 current_num = -1;
int                 thread_hold = 1;
pthread_t           threads[THREAD_NUM];




void outputMessage(int my_number, char * msg)
{
    printf("\n %s Thread: %d", msg, my_number);
}

static void check(int status, char* msg)
{
    if (status != 0) {
    printf("\nStatus = %d.  ", status);
    perror(msg);
    }
}

static void unlock_cond(void *arg)
{
    int status = pthread_mutex_unlock(&cond_mutex);
    check(status, "3:Mutex_unlock bad status\n");
}

//---< operation stuff >------------------------------------< begin >---
static int do_all_operations(int my_number)
{
    outputMessage(my_number,"\n   Starting ");
    //...
    outputMessage(my_number,"  Finishing");
    return 0;
}
//---< operation stuff >--------------------------------------< end >---


static void * performOperation(void *arg)
{
    int my_number = (int)arg;
    int 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:Mutex_lock bad status\n");
    }
    pthread_cleanup_pop(1);

    pthread_testcancel();
    status = pthread_mutex_lock(&current_mutex);
    check(status, "4:Mutex_lock bad status\n");

    
    do_all_operations(my_number);           // all activities...

    status = pthread_mutex_unlock(&current_mutex);
    check(status, "5:Mutex_unlock bad status\n");

    pthread_exit( (void*)my_number);
    return(void*)0;
}


void doThreads()
{
    int status=-1, i=0;
    void *exit_value;
    
    status = pthread_mutex_init(&cond_mutex, NULL);
    check(status, "6:Mutex_init bad status\n");

    status = pthread_mutex_init(&current_mutex, NULL);
    check(status, "7:Mutex_init bad status\n");

    status = pthread_cond_init(&cond_var, NULL);
    check(status, "8:Mutex_init bad status\n");

    for (i=0; i<THREAD_NUM; i++)
    {
    status = pthread_create(
            &threads[i],
            NULL,
            performOperation,
            (void*)i);
    check(status, "9:pthread_create bad status\n");
    }

    // clean up threads...
    status = pthread_mutex_lock(&cond_mutex);
    check(status, "10:Mutex_lock bad status\n");

    thread_hold = 0;
    status = pthread_cond_broadcast(&cond_var);
    status = pthread_mutex_unlock(&cond_mutex);
    check(status, "11:Mutex_unlock bad status\n");

    for (i=0; i<THREAD_NUM; i++)
    {
    status = pthread_join(
            threads[i],
            &exit_value);
    check(status, "12:Pthread_join bad status\n");

    if (exit_value == (void*)i)
        printf(".");
    else printf("Bad, bad, bad ...");
    }
}


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

    if (argc != 1)
    {
        cerr << "Usage: ThreadTest" << endl;
    }
    else
    {
        try
        {
            // init app...

            //---< thread stuff >--------------------------------< begin >---
            printf("\n Clock before starting threads: %ld", clock());
            doThreads();
            printf("\n\n Clock after finishing threads: %ld", clock());
            //---< thread stuff >----------------------------------< end >---

	    // terminate app...
        }
        catch(...)
        {
            cerr << "Exception caught!!!" << endl;
        }
    }

    return 0;
}
