Monitores
Setembro de 2010
Monitores
mecanismo de sincroniza¸c˜ao cl´assico referˆencia
influˆencia de conceitos de programa¸c˜ao estruturada C. A. R. Hoare, Monitors: an operating system structuring concept,Communications of the ACM, v.17 n.10, p.549-557, Oct. 1974
Per Brinch Hansen, Structured multiprogramming,
Communications of the ACM, v.15 n.7, p.574-578, July 1972
material baseado no Cap. 5 de FMPDP (Andrews)
o que s˜ ao?
constru¸c˜ao sint´atica: compilador “entende” a encapsula¸c˜ao por monitor
constru¸c˜aomonitor garante exclus˜ao m´utua para as opera¸c˜oes encapsuladas
monitor meusdados { int pegaDado ();
void poeDado (int);
}
para coopera¸c˜ao, uso de condi¸c˜oes cond umaCond;
...
while (!B) wait(umaCond);
Exclus˜ ao M´ utua
monitor BufferIlimitado {
int buf[]; int nxtfree = 0; int nxtdata = 0;
void deposit (int data) { buf[nxtfree] = data;
nxtfree = nxtfree+1;
}
int fetch () { int data;
data = buf[nxtdata];
nxtdata = nxtdata+1 return data;
} }
Exclus˜ ao M´ utua e Coopera¸c˜ ao
monitor BoundedBuffer {
int buf[SIZE]; int nxtfree = 0; int nxtdata = 0;
cond hasfree, hasdata;
void deposit (int data) {
while ((nxtfree+1)%SIZE == nxtdata) wait(hasfree);
buf[nxtfree] = data;
nxtfree = (nxtfree+1)%SIZE;
signal(hasdata);
}
int fetch () { int data;
while (nxtfree == nxtdata) wait(hasdata);
data = buf[nxtdata];
nxtdata = (nxtdata+1)%SIZE;
signal(hasfree);
}
Espera, Sinaliza¸c˜ ao e Exclus˜ ao M´ utua
espera por condi¸c˜ao n˜ao pode manter exclus˜ao m´utua
caso contr´ario a condi¸c˜ao provavelmente nunca ser´a verdadeira primitivawait deve liberar EM
e o que acontece quando um outro processo executasignal?
dois processos dentro do monitor?
Pol´ıticas propostas
1 sinaliza e continua (SC)
2 sinaliza e espera (SW)
3 sinaliza e sai
Pol´ıticas de Sinaliza¸c˜ ao
fila de entrada
fila de condição
execução no monitor chamada
monitor livre SW (sinalizador)
SW (proc sinalizado) SC (proc sinalizado)
wait
SC (sinalizador)
Pol´ıticas de Sinaliza¸c˜ ao
com SW, processo sinalizado pode ter certeza que a condi¸c˜ao
´
e verdadeira
pol´ıtica pr´oxima `a proposta inicialmente por Hoare
com SC, o pr´oprio processo sinalizador ou outros processos da fila de entrada podem ter revertido a condi¸c˜ao
sinaliza¸c˜ao passa a ser apenas “dica”
teste de condi¸c˜ao deve, quase sempre, ficar dentro de loop mais f´acil de entender!
Pol´ıticas de Sinaliza¸c˜ ao
a implementa¸c˜ao de um sem´aforo ´e um bom exemplo da diferen¸ca entre as pol´ıticas:
monitor Semaphore { int s = 0; ## s >= 0
cond pos; # signaled when s > 0 procedure Psem() {
while (s == 0) wait(pos);
s = s-1;
}
procedure Vsem() { s = s+1;
signal(pos);
} }
Passagem de Condi¸c˜ ao
t´ecnica um pouco semelhante `a passagem de bast˜ao pode ser usada:
monitor Semaphore { int s = 0; ## s >= 0
cond pos; # signaled when s > 0 procedure Psem() {
if (s == 0) wait (pos);
else s = s-1;
}
procedure Vsem() {
if (empty(pos)) s = s+1;
else signal(pos);
}
Leitores e Escritores
monitor RW_Controller {
int nr = 0, nw = 0; ## (nr == 0 or nw == 0) and nw <= 1 cond oktoread; # signaled when nw == 0
cond oktowrite; # signaled when nr == 0 and nw == 0 procedure request_read() {
while (nw > 0) wait(oktoread);
nr = nr + 1;
}
procedure release_read() { nr = nr - 1;
if (nr == 0) signal(oktowrite); # awaken one writer }
procedure request_write() {
while (nr > 0 || nw > 0) wait(oktowrite);
nw = nw + 1;
}
procedure release_write() { nw = nw - 1;
signal(oktowrite); # awaken one writer and signal_all(oktoread); # all readers }
}
outro exemplo: Barreira
monitor Barreira {
int qtos = 0; ## qtos >= 0
cond chegaram; # signaled when qtos == TODOS procedure cheguei() {
qtos++;
if (qtos < TODOS)
while (qtos < TODOS) wait(chegaram);
else
signal_all (chegaram);
} }
Fil´ osofos
Cuidados...
sinaliza¸c˜ao n˜ao embute contagem condi¸c˜ao sempre deve ser testada
ordens de entrada podem ser totalmente arbitr´arias aninhamento e deadlocks
reentrˆancia
Implementa¸c˜ oes de Monitores
exemplos cl´assicos: Concurrent Pascal, Modula, Mesa baseadas em monitores: Java e pthreads
Monitores em pthreads
locks expl´ıcitos para exclus˜ao m´utua
tipo pthread mutex tcom opera¸c˜oespthread mutex lock e pthread mutex unlock
vari´aveis de condi¸c˜ao tipo pthread cond t
opera¸c˜oes explicitamente ligam condi¸c˜oes a locks pthread cond wait(&cond, &mutex)
Monitores em pthreads: exemplo
Soma de elementos de matriz (FMPDP)
Java
classe Thread e interface Runnable
class Simple implements Runnable {
public void run () { System.out.println ("alo alo");}
}
Runnable s = new Simple;
new Thread(s).start();
...
m´etodos podem ser declarados como synchronized lock associado a cada objeto
uma fila de condi¸c˜ao por objeto
Monitores em Java: exemplo
Constru¸c˜ oes com testes impl´ıcitos
programa¸c˜ao mais f´acil
sinaliza¸c˜ao ´e um grande problema na abstra¸c˜ao de monitores implementa¸c˜ao mais dif´ıcil
especialmente em termos de eficiˆencia (quanto testar cada predicado pendente?)
al´em de monitores, j´a foram feitas v´arias propostas com esperas impl´ıcitas
Espera de condi¸c˜ oes em Guide
client) and the status of the pending requests. This tool is very powerful, but is very difficult to implement efficiently. In addition, it is far too complex for most of the usual synchronisation schemes. This analysis motivated us to define a mechanism with an expressive power between the locks and the mediators.
In Guide, synchronisation is specified as a set of constraints associated with objects, not as primitives appearing within activities. This is fully consistent with the object approach, since the specification of the synchronisation constraints is concentrated in the class that describes the object instead of being spread out in methods that use the object. In addition, this synchronisation specification is shared by all instances of the class.
Synchronisation is specified as a set of activation conditions, which are similar to Dijkstra’s guarded commands: an activation condition is attached to a method, and must be satisfied before the execution of this method may start. This condition is expressed as a function of the internal state of the object and the parameters of the invocation. If no activation condition is attached to a method, then the execution of this method is unconstrained.
4.2. Basic synchronisation model
In our language, the activation conditions are grouped in a control clause at the end of the class description. The syntax of the control clause is as follows:
CONTROL
[<method name> : <activation condition>]*
where <activation condition> is a boolean expression which may contain the following parameters: instance variables which represent the internal state of an instance, actual parameters of the method and synchronisation counters. Synchronisation based on counters was introduced in another context by Robert and Verjus [24].
Synchronisation counters are internal data that specify, for each method of a given object, the total number of invocations, the total number of completed executions, the current number of pending invocations, etc. These counters are automatically updated by the run- time system. The following counters are defined for each method m:
invoked(m) : number of invocations of method m
started(m) : number of accepted (non-blocked) invocations of method m completed(m) : number of completed executions of method m
current(m) = started(m)-completed(m) : number of current executions of method m pending(m) = invoked(m) - started(m) : number of activities blocked on method m
In addition to this basic mechanism, activation conditions can be expressed by predefined synchronisation policies (mutual exclusion and reader/writer schema).
The use of activation conditions is illustrated by the following example, which implements a buffer used for communication between activities (the type ProducerConsumer is supposed to have been introduced elsewhere):
CLASS FixedSizeBuffer IMPLEMENTS ProducerConsumer IS CONST size=100;
buffer : ARRAY[0..size-1] OF Element;
first, last: Integer = 0, 0;
METHOD Put(IN m: Element);
BEGIN buffer[last]:=m; last:=last+1 MOD size; END Put;
METHOD Get(OUT m: Element);
BEGIN m:=buffer[first]; first:= first +1 MOD size; END Get;
CONTROL
Put: (completed(Put) - completed (Get)<size) AND current(Put)=0;
Get: (completed (Put) > completed (Get)) AND current(Get)=0;
END FixedSizeBuffer.
For each control statement, the compiler produces a prologue and an epilogue section which are attached to the corresponding method. This code is executed in mutual exclusion before entering and when leaving the method. The implementation of this synchronisation scheme is described in [12].
R. Balter, S. Lacourte and M. Riveill. The Guide Language.
Computer J., vol. 37, no. 6, pp. 521-530, 1994.
Monitores
Monitores com sinaliza¸c˜ ao impl´ıcita
Buhr, P. A. and Harji, A. S. 2005. Implicit-signal monitors.
ACM Trans. Program. Lang. Syst. 27(6), Nov. 2005, 1270-1343.