SEMAPHORE OPERATIONS

advertisement
SEMAPHORE OPERATIONS
Let’s assume that it is necessary to allow to only one of two processes to execute
its critical section of code, i.e. section of code in which it must get access to critical
resource which must not be used simultaneously by more than one process.
Р1
Р2
resource
FLAG=1/0
W1: TEST FLAG, 1
JZ W1
MOV FLAG, 0
Critical section
MOV FLAG, 1
W2: TEST FLAG, 1
JZ W2
MOV FLAG, 0
Critical section
MOV FLAG, 1
Simultaneous entrance in critical section may occur on the following scenario:
instruction TEST is executed in the 1st process, and before execution of MOV FLAG, 0 ,
control is yielded to the 2nd process. Instruction TEST is executed in the 2nd process. To
escape such a situation we may use two flag variables, each of which by zero value
indicates willing of the respective process to enter critical section:
P1:
MOV FLAG1, 0
CHECK1: TEST FLAG2, 1
JZ CHECK1
Critical section
MOV FLAG1,1
P2:
MOV FLAG2, 0
CHECK2: TEST FLAG1, 1
JZ CHECK2
Critical section
MOV FLAG2,1
This solution guarantees mutual exclusion, but originates other difficulty –
deadlock of processes, or mutual blocking. If switching from the 1st process to the 2nd
occurs between commands MOV and TEST, then 2nd process also can throw its flag and
both flags will become in zero state. To provide mutual exclusion and to avoid deadlock
it is necessary to introduce 3rd flag, which shows what process has higher priority if
collision arises. This idea is implemented in Dijkstra’s algorithm, which we shall
consider farther for N processes, but it will be seen that it is not a simple one. More
simple solution can be represented by the following code:
Pi:
MOV AL, 0
TRY: XCHG AL, FLAG
TEST AL, AL
JZ TRY
Critical section
MOV FLAG,1
In this code it is used special instruction XCHG which in one instruction swaps both its
operands. This solution is not a best one because waiting process will be in the state of
active waiting (it rounds in the loop of checking register al) and wastes useless
processor’s time. Other solution follows:
Pi:
AGAIN:
MOV AL, 0
XCHG AL, SEMA
TEST AL, AL
JNZ NEXT
Call Dispatcher (process is frozen, passive waiting)
JMP SHORT AGAIN
NEXT: Critical section
Such operation of testing semaphore value in the result of which process can be
suspended is called P-operation on SEMA. Inverse operation, called V, is use to awake
sleeping process; it may be realized as follows
MOV SEMA, 1
Call Dispatcher
Dispatcher analyses queue of waiting SEMA processes and awakes one of them.
Semaphores can be used not only for mutual exclusion, but also in other synchronization
tasks, for example:
Process А
Process В
РА1: activate В
РВ1: wait signal from А
…
…
РА2: wait signal from В
РВ2: activate А
Such scheme of interaction can be implemented with the help of 2 semaphores:
WAKEA, WAKEB=0
P1
P2
РА1: V(WAKEB)
РВ1: P(WAKEB)
…
…
РА2: P(WAKEB)
РB2: V(WAKEA)
Standard synchronization tasks
Process is a calculation, application of a finite set of operations to the
finite set of data. Two processes are considered to be parallel, if execution
of the first operation of one process begins before the termination of the
other process. Resources used by several processes are called shared
resources. Critical resource is a shared resource which simultaneously can
be used no more than by one process. Interconnected processes are
processes using common shared resource or exchanging by information.
To synchronize processes means to formulate restrictions superimposed on
the order of process performing. These restrictions are assigned by means
of rules of synchronizing, which are described by means of mechanisms of
synchronizing (primitives).
Standard synchronization tasks are the following:

mutual exclusion;

dining philosophers;

producers - consumers;

readers - writers.
“Mutual exclusion” task is the following: there are several processes, program of
which contain regions, where processes retrieve to the shared resource. It’s required to
exclude a simultaneous working of the processes in this critical interval. It is necessary to
require also that delay of any process outside of its critical interval must not affect on
development of the other processes. Solution must be symmetrical for all processes (all
processes are equal). Solution mustn’t lead to global or local deadlocks. Global deadlock
means locking of the whole system of processes, and local means locking of some subset
of processes.
“Dining philosophers” task is the following: there are k plates with meal on the
round table, between them lay k forks, k=4,..7. There are k philosophers in the room,
interleaving philosophical thinking with taking a food. For each philosopher is fixed its
plate; to eat philosopher needs in two forks, moreover he can use only forks, adjacent to
his plate. It’s required to synchronize philosophers so that each of them could get for
finite time access to his plate. It is assumed that duration of eating and thinking of the
philosopher are finite, but are not known beforehand.
“Producers – consumers” task is the following: there is a limited buffer on m
places (m portions of information). It is a critical resource for processes of two types:
processes-producers which gaining access to the resource place there a portion of
information on the free place; processes-consumers which gaining access to the resource
read portion of information from it. It’s required to exclude simultaneous access of
processes to the resource. Under the full emptying of the buffer there are must be delayed
processes-consumers, under full filling of a buffer there are must be delayed processesproducers.
“Readers-writers” task is the following: there is a shared resource - a region of the
memory, to which it is required access for processes of two types: processes-readers
which may gain access to the resource simultaneously, they read information (notdamaging reading); processes-writers mutually exclude each other and readers. Two
variants of this task are known:
1) reader requested access to the resource, must get it as quickly as possible;
2) reader requested access to the resource, must get it as quickly as possible, if
there are no requests from writers. Writer, requiring access to the resource, must get it as
quickly as possible, but after servicing the readers which have come to resource before
the first writer.
Semaphores mechanism
Let S be a semaphore - a variable of a special type with integer values, on which
there are defined two operations: P and V (P - a closing, V - an opening). It’s considered
that S1. Let’s define these operations.
P(S): if S1 then the process continues to be executed, but S is decreased by 1; if
S=0, the process is suspended, and its name is transferred to the queue of processes,
waiting access to this resource (usually semaphores correspond to some resources).
Operations P and V are indivisible, i.e. with one semaphore simultaneously can work
only one process (process, started to work with the semaphore, must finish it before
switching a processor on other process in the case of quasi parallel processes or in the
case of switching other processes must not get access to this semaphore).
V(S): if there are processes in the queue to the semaphore S, one of them is
chosen and activated (is transferred to the readiness state: it is pushed in the queue of
processes, pretending on a processor time); if queue is empty then it is executed S=S+1(at
the term of result being no greater than maximal possible semaphore value; for the binary
semaphore 0S1). Operation V(S) is usually executed by the process, which comes out
of critical sections.
Semaphores mechanism allows to solve a task of the mutual exclusion:
S=1;
Process-i:
P(S);
Critical section
V(S);
It is necessary to point attention to the fact that binary semaphore variable S was
initiated by the value 1; under other variant of initialization processes may have got in the
deadlock or it will not be a solution for the mutual exclusion task.
Not careful usage of semaphore variables may lead to dead-locks conditions, for
instance in presented below two processes under simultaneous their coming to the second
operator P:
S1=1
S2=1
P(S1)
P(S2)
P(S2)
P(S1)
…
…
V(S2)
V(S1)
V(S1)
V(S2)
Meanwhile, it must be noted, that given above processes can work infinitely long
time not falling into the dead-lock.
Semaphore solution of the tasks “dining philosophers”
Let’s denote processes-philosophers by Р1, Р2, Р3, Р4 and forks by f1, f2, f3, f4.
For eating philosopher needs in two nearby forks simultaneously:
Р1
f4
Р1, P2, P3, P4 – philosophers
f1
f1, f2, f3, f4 – forks
Р4
Р2
Two forks are needed to eat
f2
f3
Р3
Algorithm of working of each philosopher assumes using of 5 semaphores (Si,
i  1,4 , S), one of which (S) is intended for the mutual exclusion of processes when
getting access to the array b, responsible for forks, and semaphore Si is intended for
suspending of i-th philosopher in the case if a result of checking the forks will find, that
necessary to him fork are absent, i=1,..,4. Let’s consider algorithm of working of the first
philosopher; the rest work similarly.
P1:
P(S[1]);
P(S);
if (f1>0)&(f4>0) then begin
f1:=0; f4:=0;
V(S);
{eating}
P(S);
f1:=1; f4:=1;
V(S);
for i:=1 to 4 do V(S[i]);
{thinking}
end
else V(S);
goto P1;
Sharing common procedures (reentrant procedures)
When common procedures are used sequentially, there local variables are to be
repeatedly initialized. Common procedures allowing time multiplexing are called
reentrant. Such procedures can be viewed as common but not critical resource for several
processes. Such procedures must contain pure not modifiable code. For this sake data
which are to be modified must be kept in local memories of respective processes,
common solution is to use for local procedure variables stack of the process.
Process 1
Process 2
CS
CS
DS
Reentrant procedure
DS
ES
ES
SS
SS
Data segment
Data segment
Extended data segment
Extended data segment
Stack segment
Stack segment
Let’s consider reentrant procedure, which multiplies two signed32-bit integers
and returns 64-bit result. Six words are allocated in stack for temporary results. To
allocate this space, 12 is subtracted from SP and result is loaded in BP, other references
are made via BP.
X
senior Х
Y
junior Х
senior Y
junior Y
х = sen х216 + jun х
y = sen y216 + jun y
We need in 4 words of result:
3
2
1
0
248
232
216
20
х  у=sen х  sen у  232 + sen у  216  jun х + sen х  216  jun у + jun х  jun у =
= (sen (sen х sen у)216 + jun (sen х sen у)) 232 + (sen (sen у jun х) 216 + jun (sen y jun
x)) 216 + (sen (sen х jun у) 216 + jun (sen х jun y)) 216 + sen (jun х jun у) 216 + jun (jun
х jun у) = (sen (sen х sen у) 248 + 232(jun (sen х sen у) + sen (sen у jun х) + sen (sen х
jun у)) +
+ 216(sen (jun х jun у) + jun (jun х sen у) + jun (sen х jun у)) + 20(jun (jun х jun у))
where:
(sen (sen х sen у)) is a 3rd word of a result;
(jun (jun х jun у)) is a 0th word of a result.
These calculations may be represented as follows:
sen Х
3
jun Х
sen Y
+
+
2
1
Layout of the program stack is following:
ADDR_X
ADDR_Y
ADDR_Z
CS
IP
BP
jun Y
0
TEMPX
TEMPY
TEMPZ
А программа:
FLAME
STRUC
TEMPZ
DW ?,?
TEMPY
DW ?,?
TEMPX
DW ?,?
SUBEBP
DW ?
SAVE_CS_IP DW ?
Z_ADDR
DW ?
Y_ADDR
DW ?
X_ADDR
DW ?
FLAME
ENDS
MULTIPLLY PROC FAR
PUSH BP
SUB SP, 12
MOV BP, SP
PUSH AX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV SI, 0
MOV BX, [BP].X_ADDR
MOV AX, [BP]
MOV [BP].TEMPX, AX
MOV [BP].TEMPX+2, AX
MOV BX, [BP].Y_ADDR
MOV AX, [BP]
MOV [BP].Y_ADDR, AX
MOV AX, [BX+2]
MOV [BP].Y_ADDR+2, AX
CMP [BP].TEMPX+2, 0
JGE CHECK_Y
NOT [BP].TEMPX
NOT [BP].TEMPX+2
ADD [BP].TEMPX, 1
ADC [BP].TEMPX+2, 0
MOV SI, 1
CHECK_Y:
CMP [BP].TEMPX+2,0
JGE START
NOT [BP].TEMPY
NOT [BP].TEMPY+2
ADD [BP].TEMPY, 1
ADC [BP].TEMPY+2, 0
XOR SI, 1
START:
MOV AX, [BP].TEMPX
MOL [BP].TEMPY
MOV [BP].TEMPZ, AX
MOV CX, DX
MOV AX, [BP].TEMPX+2
MOL [BP].TEMPY
MOV BX, DX
ADD CX, AX
ADC BX, 0
MOV DI, 0
ADC DI, 0
MOV AX, [BP].TEMPX
MOL [BP].TEMPY
ADD CX, AX
ADC BX, DX
MOV [BP].TEMPZ+2, CX
MOV CX, 0
ADC SX, DI
MOV AX, [BP].TEMPX+2
MOL [BP].TEMPY+2
ADD AX, BX
ADD DX, CX
MOV CX, [BP].TEMPZ+2
CMP SI, 0
JE STOREZ
NOT [BP].TEMPZ
NOT CX
NOT AX
NOT DX
ADD [BP].TEMPZ, 1
ADC CX, 0
ADC AX, 0
ADC DX, 0
STOREZ:
MOV BX, [BP].ADDR_Z
MOV [BX+6], DX
MOV [BX+4], AX
MOV [BX+2], CDX
MOV AX, [BP].TEMPZ
MOV [BX], AX
POP DI
POPSI
POP DX, CX, BX, AX
ADD SP, 12
POP BP
RET 6
END
Synchronization mechanisms for parallel processes
They may be classified as
 Centralized (are used in sharing memory systems – busy waiting,
semaphores, events, critical regions and conditional critical regions,
monitors, path expressions );
 Decentralized (are used in distributed systems – ADA language
rendezvous, OCCAM channels, message passing interface).
The simplest representative of former is active waiting. Let’s consider mutual
exclusion task for N processes. Array C(N) contains N elements; if C(I)=0, then i-th
process wills to enter critical section; if C(I)=1 then doesn’t want. Condition for entering
critical interval:
L:
C(I)=0
FOR J=1 TO N DO BEGIN
IF (I<>J) AND (C(J)=0) GOTO L
END;
Such solution may lead to the deadlock. To escape deadlock we need in additional array:
B(N+1), which is used to fix fact of activity of respective process. Variable queue
determines priority process (initially, 0), all elements of B, corresponding to real
processes, are 1’s initially (not active processes).
//initialization
queue=0;
B(I):=0,i=1,..,N
B(0):=1
Pi:
//i-th process, i>0
L1:
IF (queue=i) GOTO M
L:
C(i):=1
IF (B(queue)=1) * queue:=i
GOTO L1
M:
C[i]:=0
FOR J=1 TO N DO
IF (i<>J) AND (C(J)=0) GOTO L
Critical Section
C(i):=1
B(i):=1
queue:=0
If in the place marked by * 1st process will be interrupted, then – the 2nd, and son on,
then they will come to M simultaneously, and if one of them has passed to critical
section, other return to L. If nobody has entered critical section, then all return to L and
check whether B(queue)=1, meanwhile queue is equal to the number of the last process
went to M, so all processes will go to L1, and the last will go again to M and then to
critical section.
Download