master-degree-notes/Concurrent Systems/notes/3.md

3.4 KiB

Hardware primitives

Atomic R/W registers provide quite a basic computational model.

We can strenghten the model by adding specialized HW primitives, that essentially perform in an atomic way the combination of some atomic instructions. Usually, every operating system provides at least one specilized HW primitive.

Most common ones:
  • Test&set: atomic read+write of a boolean register
  • Swap: atomic read+write of a general register (generalization of the above)
  • Fetch&add: atomic read+increase of an integer register
  • Compare&swap: tests the value of a general register, returns a boolean (result of the comparison, true if it is the same).

Test&Set

Let X be a boolean register

X.test&set() :=
	tmp <- X
	X <- 1
	return tmp

(the function is implemented in an atomic way by the hardware by suspending the interruptions!)
How do we use it for MUTEX?
lock() :=
	wait X.test&set() = 0
	return


unlock() :=
	X <- 0
	return

Swap

X general register

X.swap(v) :=
	tmp <- X
	X <- v
	return tmp
How do we use it for MUTEX?
lock() :=
	wait X.swap(1) = 0
	return

unlock() :=
	X <- 0
	return

Compare&swap

X boolean register

X.compare&swap(old, new) :=
	if X = old then
		X <- new
		return true
	return false
How do we use it for MUTEX?
Initialize X at 0

lock() :=
	wait X.compare&swap(0, 1) = true
	return

unlock() :=
	X <- 0
	return

Fetch&add

Up to now, all solutions enjoy deadlock freedom, but allow for starvation. So let's use Round Robin to promote the liveness property!

Let X be an integer register; the Fetch&add primitive is implemented as follows:

X.fetch&add(v) :=
	tmp <- X
	X <- X+v
	return tmp
How do we use it for MUTEX?
Initialize TICKET and NEXT at 0

lock() :=
	my_ticket <- TICKET.fetch&add(1)
	wait my_ticket = NEXT
	return

unlock() :=
	NEXT <- NEXT + 1
	return

[!note] a>It is bounded bypass with bound n-1>

Safe registers

Atomic R/W and specialized HW primitives provide some form of atomicity. But is it possible to enforce MUTEX without atomicity?

A MRSW Safe register is a register that provides READ and WRITE such that:

  1. every READ that does not overlap with a WRITE returns the value stored in the register
  2. a READ that overlaps with a WRITE can return any possible value (of the register domain).

A MRMW Safe register behaves like a MRSW safe register, when WRITE operations do not overlap. Otherwise, in case of overlapping WRITEs, the register can contain any value (of the register domain). (Ci sta comunque lo stesso problema)

Si chiama safe nel senso che se ci sono letture overlapping siamo safe. Ma è letteralmente l'unica cosa safe che abbiamo!

This is the weakest type of register that is useful in concurrency.

Bakery Algorithm

The idea is that

  • every process gets a ticket
  • because we don't have atomicity, tickets may be not unique
  • tickets can be made unique by pairing them with the process ID
  • the smallest ticket (seen as a pair) grants the access to the CS
Initialize FLAG[i] to down and MY_TURN[i] to 0, for all i

lock(i) :=
	FLAG[i] <- up
	MY_TURN[i] <- max{MY_TURN[1],...,MY_TURN[n]}+1
	FLAG[i] <- down
	forall j != i
		wait FLAG[j] = down
		wait (MY_TURN[j] = 0 OR ⟨MY_TURN[i],i⟩ < ⟨MY_TURN[j],j⟩)

unlock(i) :=
	MY_TURN[i] <- 0

Se il ticket number è minore si ottiene l'accesso, se il ticket number è uguale, allora si vede il process ID minore.