Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Lamport's bakery algorithm

From Wikipedia, the free encyclopedia
(Redirected fromLamport's Bakery algorithm)
Logic for safely sharing computer resources
See also:Lamport's distributed mutual exclusion algorithm
This article has multiple issues. Please helpimprove it or discuss these issues on thetalk page.(Learn how and when to remove these messages)
This article includes a list ofgeneral references, butit lacks sufficient correspondinginline citations. Please help toimprove this article byintroducing more precise citations.(December 2010) (Learn how and when to remove this message)
icon
This articlerelies largely or entirely on asingle source. Relevant discussion may be found on thetalk page. Please helpimprove this article byintroducing citations to additional sources.
Find sources: "Lamport's bakery algorithm" – news ·newspapers ·books ·scholar ·JSTOR
(August 2022)
(Learn how and when to remove this message)

Lamport's bakery algorithm is a computeralgorithm devised by computer scientistLeslie Lamport, as part of his long study of theformal correctness ofconcurrent systems, which is intended to improve the safety in the usage of shared resources among multiplethreads by means ofmutual exclusion.

Incomputer science, it is common for multiple threads to simultaneously access the same resources.Data corruption can occur if two or more threads try to write into the samememory location, or if one thread reads a memory location before another has finished writing into it. Lamport's bakery algorithm is one of manymutual exclusion algorithms designed to prevent concurrent threads enteringcritical sections of code concurrently to eliminate the risk of data corruption.

Algorithm

[edit]

Analogy

[edit]

Lamport envisioned a bakery with a numbering machine at its entrance so each customer is given a unique number. Numbers increase by one as customers enter the store. A global counter displays the number of the customer that is currently being served. All other customers must wait in a queue until the baker finishes serving the current customer and the next number is displayed. When the customer is done shopping and has disposed of their number, the clerk increments the number, allowing the next customer to be served. That customer must draw another number from the numbering machine in order to shop again.

According to the analogy, the "customers" are threads, identified by the letteri, obtained from a global variable.

Due to the limitations of computer architecture, some parts of Lamport'sanalogy need slight modification. It is possible that more than one thread will get the same numbern when they request it; this cannot be avoided (without first solving the mutual exclusion problem, which is the goal of the algorithm). Therefore, it is assumed that the thread identifieri is also a priority. A lower value ofi means a higher priority and threads with higher priority will enter thecritical section first.

Critical section

[edit]

The critical section is that part of code that requires exclusive access to resources and may only be executed by one thread at a time. In the bakery analogy, it is when the customer trades with the baker that others must wait.

When a thread wants to enter the critical section, it has to check whether now is its turn to do so. It should check the numbern of every other thread to make sure that it has the smallest one. In case another thread has the same number, the thread with the smallesti will enter the critical section first.

Inpseudocode this comparison between threadsa andb can be written in the form:

// Let na - the customer number for threada, and// ia - the thread number for threada, then(na, ia) < (nb, ib)

which is equivalent to:

(na < nb) or ((na == nb) and (ia < ib))

Once the thread ends its critical job, it gets rid of its number and enters thenon-critical section.

Non-critical section

[edit]

The non-critical section is the part of code that doesn't need exclusive access. It represents some thread-specific computation that doesn't interfere with other threads' resources and execution.

This part is analogous to actions that occur after shopping, such as putting change back into the wallet.

Implementation of the algorithm

[edit]

Definitions

[edit]

In Lamport's original paper, theentering variable is known aschoosing, and the following conditions apply:

  • Words choosing [i] and number [i] are in the memory of process i, and are initially zero.
  • The range of values of number [i] is unbounded.
  • A process may fail at any time. We assume that when it fails, it immediately goes to its noncritical section and halts. There may then be a period when reading from its memory gives arbitrary values. Eventually, any read from its memory must give a value of zero.

Code examples

[edit]

Pseudocode

[edit]

In this example, all threads execute the same "main" function,Thread.In real applications, different threads often have different "main" functions.

Note that as in the original paper, the thread checks itself before entering the critical section.Since the loop conditions will evaluate asfalse, this does not cause much delay.

// declaration and initial values of global variablesEntering:array[1..NUM_THREADS]ofbool={false};Number:array[1..NUM_THREADS]ofinteger={0};lock(integeri){Entering[i]=true;Number[i]=1+max(Number[1],...,Number[NUM_THREADS]);Entering[i]=false;for(integerj=1;j<=NUM_THREADS;j++){// Wait until thread j receives its number:while(Entering[j]){/* nothing */}// Wait until all threads with smaller numbers or with the same// number, but with higher priority, finish their work:while((Number[j]!=0)&&((Number[j],j)<(Number[i],i))){/* nothing */}}}unlock(integeri){Number[i]=0;}Thread(integeri){while(true){lock(i);// The critical section goes here...unlock(i);// non-critical section...}}

Each thread only writes its own storage, only reads are shared. It is remarkable that this algorithm is not built on top of some lower level "atomic" operation, e.g.compare-and-swap. The original proof shows that for overlapping reads and writes to the same storage cell only the write must be correct.[clarification needed] The read operation can return an arbitrary number. Therefore, this algorithm can be used to implement mutual exclusion on memory that lacks synchronisation primitives, e.g., a simple SCSI disk shared between two computers.

The necessity of the variableEntering might not be obvious as there is no 'lock' around lines 7 to 13. However, suppose the variable was removed and two processes computed the sameNumber[i]. If the higher-priority process was preempted before settingNumber[i], the low-priority process will see that the other process has a number of zero, and enters the critical section; later, the high-priority process will ignore equalNumber[i] for lower-priority processes, and also enters the critical section. As a result, two processes can enter the critical section at the same time. The bakery algorithm uses theEntering variable to make the assignment on line 6 look like it was atomic; processi will never see a number equal to zero for a processj that is going to pick the same number asi.

When implementing the pseudo code in a single process system or undercooperative multitasking, it is better to replace the "do nothing" sections with code that notifies the operating system to immediately switch to the next thread. This primitive is often referred to asyield.

Lamport's bakery algorithm assumes asequential consistency memory model. Few, if any, languages or multi-core processors implement such a memory model. Therefore, correct implementation of the algorithm typically requires inserting fences to inhibit reordering.[1]

PlusCal code

[edit]

We declare N to be the number of processes, and we assume that N is anatural number.

CONSTANT NASSUME N \in Nat

We define P to be the set {1, 2, ... , N} of processes.

P == 1..N

The variables num and flag are declared as global.

--algorithm AtomicBakery {variable num = [i \in P |-> 0], flag = [i \in P |-> FALSE];

The following definesLL(j, i) to be true iff<<num[j], j>> is less than or equal to<<num[i], i>> in the usuallexicographical ordering.

define { LL(j, i) == \/ num[j] < num[i]                     \/ /\ num[i] = num[j]                        /\ j =< i       }

For each element in P there is a process with local variables unread, max and nxt. Steps between consecutive labels p1, ..., p7, cs are considered atomic. The statement with(x\in S){ body} sets id to a nondeterministically chosen element of the set S and then executes body. A step containing the statement await expr can be executed only when the value of expr isTRUE.

process (p \in P)  variables unread \in SUBSET P,             max \in Nat,             nxt \in P;{p1: while (TRUE) {      unread := P \ {self} ;      max := 0;      flag[self] := TRUE;p2:   while (unread # {}) {        with (i \in unread) { unread := unread \ {i};                              if (num[i] > max) { max := num[i]; }         }       };p3:   num[self] := max + 1;p4:   flag[self] := FALSE;      unread := P \ {self} ;p5:   while (unread # {}) {        with (i \in unread) { nxt := i ; };        await ~ flag[nxt];p6:     await \/ num[nxt] = 0              \/ LL(self, nxt) ;        unread := unread \ {nxt};        } ;cs:   skip ;  \* the critical section;p7:   num[self] := 0; }}}

Java code

[edit]

We use the AtomicIntegerArray class not for its built in atomic operations but because its get and set methods work like volatile reads and writes. Under theJava Memory Model this ensures that writes are immediately visible to all threads.

AtomicIntegerArrayticket=newAtomicIntegerArray(threads);// ticket for threads in line, n - number of threads// Java initializes each element of 'ticket' to 0AtomicIntegerArrayentering=newAtomicIntegerArray(threads);// 1 when thread entering in line// Java initializes each element of 'entering' to 0publicvoidlock(intpid)// thread ID{entering.set(pid,1);intmax=0;for(inti=0;i<threads;i++){intcurrent=ticket.get(i);if(current>max){max=current;}}ticket.set(pid,1+max);entering.set(pid,0);for(inti=0;i<ticket.length();++i){if(i!=pid){while(entering.get(i)==1){Thread.yield();}// wait while other thread picks a ticketwhile(ticket.get(i)!=0&&(ticket.get(i)<ticket.get(pid)||(ticket.get(i)==ticket.get(pid)&&i<pid))){Thread.yield();}}}// The critical section goes here...}publicvoidunlock(intpid){ticket.set(pid,0);}

See also

[edit]

References

[edit]
  1. ^Chinmay Narayan, Shibashis Guha, S.Arun-KumarInferring Fences in a Concurrent Program Using SC proof of Correctness

External links

[edit]
Retrieved from "https://en.wikipedia.org/w/index.php?title=Lamport%27s_bakery_algorithm&oldid=1332615171"
Category:
Hidden categories:

[8]ページ先頭

©2009-2026 Movatter.jp