Filip Ek Johansson. 2017-03-15. 19970821-6578
Operativsystem, HI2015

Anledningen till att uppg3a nästan alltid bara skriver ut en massa nollor är just för att deadlock uppstår, till skillnad från i uppg3b där det inte uppstår.

Titta på följande utdraget från a respektive b:

== uppg3a.c ==

void* tf1(void *par) {
  ...
    pthread_mutex_lock(&m1);
    sleep(1);                  <--- 1
    pthread_mutex_lock(&m2);
    ...
    pthread_mutex_unlock(&m1); <--- 2
    pthread_mutex_unlock(&m2);
  ...
}

Här låser tråd 1 mutex m1 och sover sedan i en sekund. Samtidigt låser tråd 2 mutex m2 och sover också i en sekund. När båda trådarna slutat sova vill de båda ha varandras mutex.

pthread_mutex_lock är ett blokerande anrop, så båda trådarna sitter och väntar på tills mutexen är släppt, vilken aldrig kommer att hända eftersom det först sker ifall någon tråd låst båda samtidigt. Programmet kommer med andra ord aldrig till (2) där pthread_mutex_unlock låser upp mutex så den kan användas igen.

Vi har cyklisk väntan, odelbara resurser och ingen kan ta mutex ifrån trådarna. Därför uppstår deadlock. Ingen tråd kan då skriva in sitt ID i thread-variablen.


Å andra sidan i uppgift b:

== uppg3b.c ==

void* tf1(void *par) {
  ...
    pthread_mutex_lock(&m1);
    if(pthread_mutex_trylock(&m2))  <--- 1
    {
      ...
    }
    else pthread_mutex_unlock(&m1); <--- 2
  ...
}

I utraget från b kan vi se att om tråden inte kan få tag på båda mutexarna (1) ger den upp och släpper allt den har (2). Det samma gäller för båda trådarna i programmet.
På så sätt uppstår inte deadlock för nu uppfyller programmet inte de tre reglerna för att det ska uppstå.
Vi har inte längre cyklisk väntan eftersom processen använder pthread_mutex_trylock istället för pthread_mutex_lock.
Trylock returnerar ifall den lyckades låsa en mutex eller inte och på så sätt kan vi ta reda på ifall mutexen redan används eller är ledig. Om den är ledig returneras true och då tråden använda resursen.


