#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
//gcc uppg3.c -o uppg3 -lpthread

/*
 * De tre nödvändiga villkoren för deadlock är Mutual exclusion - icke delbara resurser,
 * circular wait - cyklisk väntan och no preemption - icke återtagande av resurs.
 * Den utgivna koden hade alla tre villkor vilket ledde till att deadlock kunde uppstå.
 * Min lösning inriktade sig på att ta bort 'hold and wait', en del av cyklisk väntan, där båda trådarna tar en resurs och vill låsa den andra.
 * då båda resurserna är låsta och det finns inget återtagande av resurs kommer dom att hålla sin egna resurs och vänta (hold and wait) på att
 * den andra tråden släpper sin resurs. Jag löste det genom att använda pthread_mutex_trylock i båda trådarna.
 * Detta gör så att nu i koden kommer trådarna att låsa resurs1, därefter kollar tråden om resurs2 är låst med hjälp av mutex_trylock.
 * är resursen olåst skickar trylock tillbaka en '0', den går in i if-satsen och låser resurs2 och utför sin kod sen låser upp båda resursena.
 * om resurs2 skulle vara upptagen returneras ett annat värde. Tråden går då in i else-satsen där den låser upp sin egna resurs så att
 * den andra tråden kan använda båda resursena.
 *
 * På detta sett har vi tagit bort en av deadlocks 3 nödvändiga villkor vilket gör att deadlock inte längre kan uppstå i programmet.
 *
 */


pthread_mutex_t resource[5];
char res_str[] = "00000";

int pick(){return rand()%5;}
int pick2(){return rand()%2+1;}

void* t1 (void * p) {
  int r1, r2;
  while(1) {
    r1=pick(); r2=pick();
    sleep(pick2());
    	
		pthread_mutex_lock(&resource[r1]);
   		res_str[r1]='1';
   		if(!pthread_mutex_trylock(&resource[r2]))
		{
    		res_str[r2]='1';
   		sleep(pick2());
   		res_str[r1]='0';
    		res_str[r2]='0';
   		pthread_mutex_unlock(&resource[r1]);
    		pthread_mutex_unlock(&resource[r2]);
		}
		else
		{
		res_str[r1]='0';
		pthread_mutex_unlock(&resource[r1]);
		}
  }
}

void* t2 (void * p) {
  int r1, r2;
  while(1) {
    r1=pick(); r2=pick();
    sleep(pick2());
    pthread_mutex_lock(&resource[r1]);
    res_str[r1]='2';
    if(!pthread_mutex_trylock(&resource[r2]))
{
    res_str[r2]='2';
    sleep(pick2());
    res_str[r1]='0';
    res_str[r2]='0';
    pthread_mutex_unlock(&resource[r1]);
    pthread_mutex_unlock(&resource[r2]);
}
else
{
	res_str[r1]='0';
	pthread_mutex_unlock(&resource[r1]);
}
  }
}

main() {
  int i=0,n;
  pthread_t id1, id2;
  pthread_create(&id1,NULL,&t1,NULL);
  pthread_create(&id2,NULL,&t2,NULL);
  while(i++<30)
  {
    sleep(1);
    printf("%2d: %s\n", i, res_str);
  }
}
