#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#define MAX_LOOP_THREAD 1000
#define EXIT_CHAR 'c'

uint32_t sharedVar1 = 0;
uint32_t sharedVar2 = 0;

pthread_mutex_t mtxForShV1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mtxForShV2 = PTHREAD_MUTEX_INITIALIZER;

void *thread1_main(void *arg)
{
    int32_t loop = 0;
    int32_t tmp = 0;

    while (loop<MAX_LOOP_THREAD)
    {
        pthread_mutex_lock(&mtxForShV1);

        sharedVar1 = 11;
        tmp = sharedVar1;

        usleep(50000); //50ms - Assuming that there is something to operate here

        if (tmp != sharedVar1) {
            printf("thread:%d, sharedVar1= %u and tmp = %d differ\n", *(int*)arg, sharedVar1, tmp);
        }
        else {
            printf("thread:%d, sharedVar1= %u, tmp = %d\n", *(int*)arg, sharedVar1, tmp);
        }

        pthread_mutex_unlock(&mtxForShV1);
        
        sharedVar2 = 12;
        tmp = sharedVar2;

        usleep(50000); //50ms - Assuming that there is something to operate here

        if (tmp != sharedVar2) {
            printf("thread:%d, sharedVar2 = %u and tmp = %d differ\n", *(int*)arg, sharedVar2, tmp);
        }
        else {
            printf("thread:%d, sharedVar2 = %u, tmp = %d\n", *(int*)arg, sharedVar2, tmp);
        }

        loop++;
    }

    pthread_exit((void *) 0);

    return NULL;
}

void *thread2_main(void *arg)
{
    int32_t loop = 0;
    int32_t tmp = 0;

    while (loop<MAX_LOOP_THREAD)
    {
        pthread_mutex_lock(&mtxForShV1);
        
        sharedVar2 = 22;
        tmp = sharedVar2;

        usleep(50000); //50ms - Assuming that there is something to operate here

        if (tmp != sharedVar2) {
            printf("thread:%d, sharedVar2 = %u and tmp = %d differ\n", *(int*)arg, sharedVar2, tmp);
        }
        else {
            printf("thread:%d, sharedVar2 = %u, tmp = %d\n", *(int*)arg, sharedVar2, tmp);
        }

        sharedVar1 = 21;
        tmp = sharedVar1;

        usleep(50000); //50ms - Assuming that there is something to operate here

        if (tmp != sharedVar1) {
            printf("thread:%d, sharedVar1= %u and tmp = %d differ\n", *(int*)arg, sharedVar1, tmp);
        }
        else {
            printf("thread:%d, sharedVar1= %u, tmp = %d\n", *(int*)arg, sharedVar1, tmp);
        }
        
        pthread_mutex_unlock(&mtxForShV1);

        loop++;
    }

    pthread_exit((void *) 0);

    return NULL;
}

void *thread3_main(void *arg)
{
    int32_t input = 0;

    while (EXIT_CHAR !=input)
    {
        input = getchar();
    }

    printf("thread: %d, got character %c\n",*(int*)&arg, input);

    pthread_exit((void *) 0);

    return NULL;
}

int main(void)
{
    int32_t status, errStatus;
    static int32_t data1 = 1, data2 = 2, data3 = 3;
    pthread_t thread1, thread2, thread3;
	
    errStatus = pthread_create(&thread1, NULL, &thread1_main, &data1);
    if (0 != errStatus) {
        printf("thread1: pthread_create return errno : %d\n", errStatus);
        exit(0);
    }

    errStatus = pthread_create(&thread2, NULL, &thread2_main, &data2);
    if (0 != errStatus) {
        printf("thread2: pthread_create return errno : %d\n", errStatus);
        exit(0);
    }

    errStatus = pthread_create(&thread3, NULL, &thread3_main, &data3);
    if (0 != errStatus) {
        printf("thread3: pthread_create return errno : %d\n", errStatus);
        exit(0);
    }
    else {
        errStatus = pthread_join(thread3, (void**)&status);
        if (0 != errStatus) {
            printf("thread3: pthread_join return errno : %d\n", errStatus);
            exit(0);
        }

        errStatus = pthread_join(thread2, (void**)&status);
        if (0 != errStatus) {
            printf("thread2: pthread_join return errno : %d\n", errStatus);
            exit(0);
        }

        errStatus = pthread_join(thread1, (void**)&status);
        if (0 != errStatus) {
            printf("thread1: pthread_join return errno : %d\n", errStatus);
            exit(0);
        }
    }

	return 0;
}