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

/* Kommentar

I originalkoden använder man sig endast av "pthread_mutex_lock" 
som då väntar
på att den angivna resursen blir ledig. Detta kan leda till 
en cyklist väntan
om t.ex. tråd 1 väntar på en resurs som ägs av tråd två 
som i sin tur väntar
på en resurs som ägs av tråd 1, de står alltså och 
väntar på varandra och att
resursen ska bli ledig vilket händer under körningen.

Jag har däremot infört "pthread_mutex_trylock" i båda 
trådarna på andra stället där
låsning inträffar. Det som händer nu är att en tråd kommer 
vänta på sin första
resurs och därefter försöka låsa andra resursen. Lyckas den 
låsa andra resursen
kommer den markera den och sleepa i ett litet tag och därefter 
unlocka båda
resurserna. Det "pthread_mutex_trylock" gör till skillnad 
från "pthread_mutex_lock"
är att den FÖRSÖKER låsa en resurs. Resursen blir låst om 
funktionen lyckas men den
står inte och väntar på resursen om den redan är låst av 
någon tråd vilket alltså
förhindrar deadlock i mitt fall.

Jag har även flyttat första sleep i varje trådfunktion 
så att varje tråd hinner ta en
resurs i början.

*/

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

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

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