° If processes Pi and Pj receive the same number, ± if i <= j, then P is served first; else Pj is served first. ° The numbering scheme always generates numbers in increasing order of enumeration; i.e. 1,2,3,3,3,3,4,4,5,5
Bakery Algorithm (cont.) ° Notation - ± Lexicographic order(ticket#, process id#) ° ( a , b ) < ( c , d ) if ( a < c ) or if (( a = c ) and ( b < d )) ° max( a 0 ,…. a n -1 ) is a number, k , such that k >= a i for i = 0,…, n -1 ° Shared Data var choosing : array [0.. n -1] of boolean ;(initialized to false ) number : array [0.. n -1] of integer ; (initialized to 0)
Bakery Algorithm (cont.) repeat choosing [ i ] := true ; number [ i ] := max( number , number ,…, number [ n -1]) +1; choosing [ i ] := false ; for j := 0 to n -1 do begin while choosing [j] do no-op ; while number [ j ] <> 0 and ( number [ j ] ,j ) < ( number [ i ] ,i ) do no-op; end ; critical section number [ i ]:= 0; remainder section until false;
Hardware Solutions for Synchronization ° Mutual exclusion solutions presented depend on memory hardware having read/write cycle. ± If multiple reads/writes could occur to the same memory location at the same time, this would not work. ± Processors with caches but no cache coherency cannot use the solutions ° In general, it is impossible to build mutual exclusion without a primitive that provides some form of mutual exclusion. ° How can this be done in the hardware???
Synchronization Hardware ° Test and modify the content of a word atomically - Test-and-set instruction function Test-and-Set ( var target : boolean ): boolean ; begin Test-and-Set := target ; target := true ; end ; ° Similarly “ SWAP ” instruction
Mutual Exclusion with Test-and-Set ° Shared data: var lock: boolean (initially false) ° Process Pi repeat while Test-and-Set ( lock ) do no-op; critical section lock := false; remainder section until false;
Bounded Waiting Mutual Exclusion with Test-and-Set var j : 0.. n -1; key : boolean ; repeat waiting [ i ] := true ; key := true ; while waiting [i] and key do key := Test-and-Set(lock) ; waiting [ i ] := false ; critical section j := j + 1 mod n; while ( j <> i ) and ( not waiting [ j ]) do j := j + 1 mod n ; if j = i then lock := false ; else waiting [ j ] := false ; remainder section until false ;
Semaphore ° Semaphore S - integer variable ± used to represent number of abstract resources ° Can only be accessed via two indivisible (atomic) operations wait ( S ): while S <= 0 do no-op S := S -1; signal (S): S := S +1; ± P or wait used to acquire a resource, decrements count ± V or signal releases a resource and increments count ± If P is performed on a count <= 0, process must wait for V or the release of a resource.
Example: Critical Section for n Processes ± Shared variables var mutex : semaphore initially mutex = 1 ± Process P i repeat wait ( mutex ) ; critical section signal ( mutex ) ; remainder section until false
Semaphore as a General Synchronization Tool ° Execute B in P j only after A execute in P i ° Use semaphore flag initialized to 0 ° Code: P P i j . . . . . . A wait ( flag ) signal ( flag ) B
Problem... ° Busy Waiting, uses CPU that others could use. This type of semaphore is called a spinlock . ± OK for short times since it prevents a context switch. ° For longer runtimes, need to modify P and V so that processes can block and resume.
Semaphore Implementation ° Define a semaphore as a record type semaphore = record value : integer ; L : list of processes ; end ; ° Assume two simple operations ° block suspends the process that invokes it.
- One '20
- producer, monitor, Semaphore