/**********************************************
 * Programming with pthread: pthreadProg3.c   
 * Compile: cc -Wall -lpthread pthreadProg3.c
 * Execute it as $ ./pthreadProg3 5          
 * ********************************************/

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

void * thread1(void *) ;
void * thread2(void *) ;

int fact(int n){
     if(n == 0) return 1 ;
     return n*fact(n-1) ;
}

int fib(int n) {
     int f0 = 0, f1 = 1, i ;

     if(n == 0) return f0 ;
     if(n == 1) return f1 ;
     for(i=2; i<=n; ++i) {
          int temp = f0 ;

          f0 = f1 ;
          f1 = f0 + temp ;     
     }
     return f1 ;
}


int main(int count, char *vect[]) { // argument is data for times
     pthread_t thID1, thID2; // thread ID
     int n ;

     if(count < 2) {
          printf("No argument for times\n") ;
          exit(0) ;
     }
     
     n = atoi(vect[1]) ;
     printf("In the main thread: &n = %p\n", &n) ;

     pthread_create(&thID1, NULL, thread1, &n) ; // 1st child thread1
     pthread_create(&thID2, NULL, thread2, &n) ; // 2nd child thread2
     
     pthread_join(thID2, NULL) ; // 2nd thread joins
     pthread_join(thID1, NULL) ; // 1st thread joins    

     return 0 ;
}

void *thread1(void *vp) { // Address of n is passed
     int i, *p ;

     p = (int *) vp ;
     printf("\t In thread 1: &i = %p\n", &i) ;
     for(i=0; i<=*p; ++i) {
          printf("\t%d! = %d\n", i, fact(i)) ; 
          sleep(1) ;
     }
     return NULL ;
}

void *thread2(void *vp) { // Address of n is passed
     int i, *p ;

     p = (int *) vp ;
     printf("\t\t\tIn thread 2: &i = %p\n", &i) ;
     for(i=0; i<=*p; ++i) {
          printf("\t\t\tfib(%d) = %d\n", i, fib(i)) ; 
          sleep(2) ;
     }     
     return NULL ;
}

