uppg3a:

När t1 låser m1 så sover den i en sekund innan den försöker låsa m2.
t2 gör liknande fast låser m2 först, sover i en sekund för att sedan låsa m1.

Problemet med detta är att båda låsen görs med hjälp av mutex_lock.
På manualsidan för mutex_lock står följande:

 "If the  mutex  is  already  locked,  the  calling
 thread  shall  block until the mutex becomes available.  This operation
 shall return with the mutex object referenced by mutex  in  the  locked
 state with the calling thread as its owner."

Detta innebär att om en mutex är låst så kommer tråden att vänta tills den är tillgänglig.
Då t1 låser m1 först och sedan sover i en sekund innan den låser m2 så finns det risk att
t2 låser m2 under den period som t1 sover (eller tvärtom). Detta kommer då leda till att:

1. t1 låst m1 och väntar nu på att m2 ska bli tillgängligt.
2. t2 låst m2 och väntar nu på att m1 ska bli tillgängligt.

Båda trådarna kommer vänta på att den andra släpper vilket aldrig kommer ske, vi får alltså
deadlock här. När deadlock sker på denna program (uppg3a) så kommer main att printa 0 den
resterande tiden av programmet.

Detta behöver inte betyda att vi alltid kommer få deadlock, men med kod som denna är risken
stor.


uppg3b:

I denna program har man en ganska liknande början som till den tidigare då t1 försöker låsa
m1 och t2 försöker låsa m2, båda med hjälp av mutex_lock. Skillnaden kommer efter denna del
då trådarna nu istället för att försöka låsa den andra mutexlåset med mutex_lock använder
sig av mutex_trylock!

På manualsidan för mutex_trylock står följande:

"The   pthread_mutex_trylock()   function   shall   be   equivalent   to
 pthread_mutex_lock(),  except  that  if  the mutex object referenced by
 mutex is  currently  locked  (by  any  thread,  including  the  current
 thread),  the  call  shall  return  immediately."

Detta innebär att den försöker låsa ett mutexlås på samma sätt som en vanlig mutex_lock,
men att om den inte lyckas då låset redan är låst så blir den inte blockerad. Den forsätter
helt enkelt med koden genom att returnera (värdet på return beror på om den lyckades låsa eller inte). Lägg dock märke till att mutex_trylock ligger inom en if-sats.
Detta gör så att om den lyckas låsa mutex_låset så kör den koden inuti if-satsen,
vid misslyckande så kommer den inte in. Det hade varit dumt om den körde koden även om den inte lyckas låsa.

Anledningen till att detta hjälper oss att undvika deadlock är att de inte bara sitter och
väntar på att något ska hända. Sedan att om en tråd inte lyckas köra trylock så kör den
istället en else-sats som innehåller en mutex_unlock. Vi må undvika deadlock med hjälp av
trylock, men detta kommer inte spela någon roll om låset förblir låst! Vi kommer istället få
en så kallad livelock (koden körs men resultatet blir densamma som deadlock)!

För att undvika livelock så har programmeraren tillåtit återtagande av resurser med hjälp
av mutex_unlock.

På manualsidan för mutex_unlock står följande:

"The   pthread_mutex_trylock()   function   shall   be   equivalent   to
 pthread_mutex_lock(),  except  that  if  the mutex object referenced by
 mutex is  currently  locked  (by  any  thread,  including  the  current
 thread),  the  call  shall  return  immediately."

Alltså som namnet säger så låser mutex_unlock upp ett mutex_lås.

vi får då följande algoritm (vi följer t1 för enkelhetens skull):

1. Sov i ett slumpmässigt antal sekunder (detta fanns inte i uppg3a, den behövs inte för att förhindra deadlock men är bra inom denna kod för att sänka antalet gånger en livelock kan uppkomma)

2. Vi låser m1, om den redan är låst så väntar vi.

3. vi försöker låsa m2:
	a. om vi lyckas låsa så sätter vi thread = 1, efter en slumpmässad tid sätter vi 	    tillbaka den till 0. Sedan låser vi upp m1 och m2 så de blir tillgängliga.
	b. om vi inte lyckas låsa så låser vi upp m1 så att den blir tillgänglig för nästa 		   tråd.

4. Rince and repeat, kör om från punkt 1 i algoritmen.


Vi kan då se att vi har motverkat deadlock då vi inom algoritmen släpper vår resurs så att en annan tråd kan ta den. Vi har också motverkat livelock med hjälp av en slumpmässig sleep i början av algoritmen så att båda inte låser m1 respektive m2, sedan släpper trådarna låsen då de inte lyckas med trylock, och sedan försöker igen samtidigt osv.

