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

// Ett villkor till att deadlock ska kunna uppstå är att en tråd låst en resurs och sedan försöker låsa en annan resurs
// Deadlock kan då uppstå om t.ex tråd 1 redan låst resurs 1 och försöker låsa resurs 2, samtidigt som tråd 2 håller i resurs 2 och försöker låsa resurs 1
// Trådarna väntar då oändligt på att den andra tråden ska släppa sin resurs och därav deadlock.

// Detta var fallet i den omodifierade koden. Om tråd1 slumpade r1, r2 = 1, 2 och tråd2 slumpade r1, r2 = 2, 1
// så uppstår det deadlock om en context switch sker när raden:
// res_str[r1] ='1'; exekveras. Detta är om den andra tråden hinner exekvera sin pthread_mutex_lock(&resource[r1]); efter att denna context switchen skett

// Detta har jag motverkat i mina modifikationer genom att varje tråd bara låser den resurs som tråden skall arbeta med i sitt nästa kommando.
// Det betyder alltså att varje tråd bara kan hålla i en låst resurs åt gången och det nämnda villkoret för att deadlock skall uppstå kan aldrig uppfyllas


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';
    pthread_mutex_unlock(&resource[r1]);
    pthread_mutex_lock(&resource[r2]);
    res_str[r2]='1';
    pthread_mutex_unlock(&resource[r2]);
    sleep(pick2());
    pthread_mutex_lock(&resource[r1]);
    res_str[r1]='0';
    pthread_mutex_unlock(&resource[r1]);
    pthread_mutex_lock(&resource[r2]);
    res_str[r2]='0';
    pthread_mutex_unlock(&resource[r2]);
  }
}

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

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);
  }
}
