/*Example:*/

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

struct phonebookentry {
       char name[64];
       long int phonenumber;
       char flags[16];
};

struct arguments {
       struct phonebookentry *apbe;
       long int phonenumber;
};

pthread_mutex_t lock;
pthread_cond_t cond;
int data_available=0;
int done=0;

void *fetch(void *);

#define NUM_PHONEBOOK_ENTRIES 4
#define NUM_THREADS 10
#define LOOKUPS_TO_DO 10

struct phonebookentry
phonebook[NUM_PHONEBOOK_ENTRIES]={{"alex",9999999,"home"},{"david",2222222,"mobile"},{"matthew",3333333,"work"},{"sarah",1234567,"mobile"}};

int main (void)
{
       struct arguments *arg;
       struct phonebookentry *results;
       pthread_t thread_id[NUM_THREADS];
       long int
i,lookup_numbers[LOOKUPS_TO_DO]={9999999,2222222,3333333,4444444,9999999,2222222,3333333,4444444,1234567,7654321};

       /*initialize*/
       pthread_mutex_init(&lock,NULL);
       pthread_cond_init(&cond,NULL);
       arg=calloc(1,sizeof(struct arguments));
       results=calloc(LOOKUPS_TO_DO,sizeof(struct phonebookentry));

       /*here we strart two worker threads */
       for(i=0;i<NUM_THREADS;i++)
         pthread_create(&thread_id[i], NULL, fetch, (void*)arg);

       /*now we make them do work */
       for(i=0;i<LOOKUPS_TO_DO;i++)
         {
           /*give thread something to do*/
           pthread_mutex_lock(&lock);

           arg->phonenumber=lookup_numbers[i];
           arg->apbe=&(results[i]);
           data_available=1;

           pthread_cond_signal(&cond);
           pthread_mutex_unlock(&lock);
           /*wait until thread receives the data*/
           while(data_available==1)
             {
               /*do nothing*/
             }
         }

       /* wait for all threads to finish */
       printf("Waiting for all lookups to finish\n");

       while(done<LOOKUPS_TO_DO)
             {
               /*do nothing*/
               sleep(1);
             }

       for(i=0;i<LOOKUPS_TO_DO;i++)
         printf("Result: Name:%s,
Number:%d\n",results[i].name,results[i].phonenumber);

       printf("All work done...killing threads and cleaning up\n");
       for(i=0;i<NUM_THREADS;i++)
         pthread_kill(thread_id[i],9);
       pthread_mutex_destroy(&lock);
       pthread_cond_destroy(&cond);
       free(arg);
       free(results);
       return 0;
}

void *fetch(void *arg)
{
 long int i=0,number;
 struct phonebookentry *npbe;
 printf("Thread %d is alive!!!\n",(int)pthread_self());
 while(1)
   {
     pthread_mutex_lock(&lock);
     if(data_available==0)
       {
         pthread_cond_wait(&cond,&lock);
       }

     number=((struct arguments *)arg)->phonenumber;
     npbe=((struct arguments *)arg)->apbe;
     data_available=0;
     pthread_mutex_unlock(&lock);

     /* fetch value from a database */
     printf("Thread %d: Fetch started, looking for %d\n",(int)pthread_self(),number);
     i=0;
     while(i<1000*number) /*simulate long database lookup*/
       i=i+1;

     for(i=0;i<NUM_PHONEBOOK_ENTRIES;i++) /*doing the actual lookup*/
       {
         if(phonebook[i].phonenumber==number)
           {
             *npbe=phonebook[i];
             break;
           }
       }

     if (i<NUM_PHONEBOOK_ENTRIES)
       printf("Thread %d: Found name %s, number %d\n",(int)pthread_self(),npbe->name,npbe->phonenumber);
     else
       printf("Thread %d: %d Number not found\n",number, (int)pthread_self());

     done++;
   }
}

