Unidade 6: Sincronização de Processos • • • • • • • • • Contexto O problema da seção crítica Hardware para sincronização Semáforos Problemas clássicos de sincronização Regiões críticas Monitores Sincronização no Solaris 2 Transação atômica Operating System Concepts 6.1 Silberschatz and Galvin1999 Contexto • • • Acesso concorrente a dados compartilhados pode levar a inconsistências. Para manter a consistência de dados necessitam-se de mecanismos que garantem a execução de processos cooperativos na ordem certa. A solução do problema do buffer limitado (capítulo 4) permite que tenha no máximo n – 1 itens no buffer no mesmo tempo. Uma solução que usa todos os buffers não é simples. – Suponhamos que modificamos o código de produtor e consumidor colocando uma variável counter, inicializada em 0 e incrementada a cada vez que um item novo é colocado no buffer Operating System Concepts 6.2 Silberschatz and Galvin1999 Bounded-Buffer • • Shared data type item = … ; var buffer array [0..n-1] of item; in, out: 0..n-1; counter: 0..n; in, out, counter := 0; Producer process repeat … produce an item in nextp … while counter = n do no-op; buffer [in] := nextp; in := in + 1 mod n; counter := counter +1; until false; Operating System Concepts 6.3 Silberschatz and Galvin1999 Bounded-Buffer (Cont.) • • Consumer process repeat while counter = 0 do no-op; nextc := buffer [out]; out := out + 1 mod n; counter := counter – 1; … consume the item in nextc … until false; As linhas de código: – counter := counter + 1; – counter := counter - 1; devem ser executados atomicamente. Operating System Concepts 6.4 Silberschatz and Galvin1999 O problema da seção crítica • • • • n processos concorrem para usar algum dado compartilhado Cada processo tem um trecho de código chamado seção crítica no qual os dados compartilhados estão sendo acessados. O problema: ter certeza que enquanto um processo está executando dentro da sua seção crítica, nenhum outro processo é permitido de executar na sua seção crítica. Estrutura de processo Pi repeat seção de entrada seção crítica seção de saída seção restante until false; Operating System Concepts 6.5 Silberschatz and Galvin1999 Solução do problema da seção crítica 1. Exclusão mútua. Se processo Pi está executando dentro da sua seção crítica, nenhum outro processo pode executar na sua seção crítica. 2. Progresso. Se nenhum processo está executando na sua seção crítica e existe alguns processos que desejam entrar nas suas respetivas seções críticas, então a seleção do processo que vai entrar na seção crítica não pode ser adiada por causa de um processo que está na sua seção restante. 3. Espera limitada. Deve existir um limite para o número de vezes que outros processos são permitidos de entrar nas suas seções críticas depois que um processo tenha feito uma solicitação para entrar a seção crítica dele e antes que esta solicitação tenha sido atendida. Suponha que todo processo executa na seção crítica em velocidade não-zero. Não faça nenhuma suposição sobre a velocidade relativa dos n processos. Operating System Concepts 6.6 Silberschatz and Galvin1999 Initial Attempts to Solve Problem • • Somente dois processos, P0 e P1 Estrutura geral do processo Pi (outro processo é Pj) repeat seção de entrada seção crítica seção de saída seção restante until false; • Processos são permitidos de compartilhar alguns variáveis para poder sincronizar suas ações. Operating System Concepts 6.7 Silberschatz and Galvin1999 Algoritmo 1 • • Variáveis compartilhadas: – var turn: (0..1); inicialmente turn = 0 – turn - i Pi pode entrar dentro da sua seção crítica Processo Pi repeat while turn i do no-op; seção crítica turn := j; seção restante until false; • Satisfaz exclusão mútua, mas não o progresso: Processo Pi não pode executar duas vezes em seguida a seção critica sem que Pj tenha executado uma vez a seção crítica dele Operating System Concepts 6.8 Silberschatz and Galvin1999 Algoritmo 2 • • Variáveis compartilhadas – var flag: array [0..1] of boolean; inicialmente flag [0] = flag [1] = false. – flag [i] = true Pi pode entrar dentro da sua seção crítica Process Pi repeat flag[i] := true; while flag[j] do no-op; seção crítica flag [i] := false; seção restante until false; • Satisfaz exclusão mutua, mas não a condição de progresso. Operating System Concepts 6.9 Silberschatz and Galvin1999 Algoritmo 3 • • Combinação das variáveis compartilhadas de algoritmo 1 e 2. Processo Pi repeat flag [i] := true; turn := j; while (flag [j] and turn = j) do no-op; seção crítica flag [i] := false; seção restante until false; • preenche todas as condições e resolve o problema da seção crítica para dois processos. Operating System Concepts 6.10 Silberschatz and Galvin1999 Algoritmo do Banco Seção crítica para n processos • • • Antes de entrara na sua seção crítica o processos recebe um número (ficha). Quem está com número menor entra na seção crítica. Se procesos Pi e Pj recebem o mesmo número, se i < j, então Pi é servido primeiro; senão Pj é servido primeiro. O esquema de enumeração sempre gera números em ordem crescente, ou seja, 1,2,3,3,3,3,4,5... Operating System Concepts 6.11 Silberschatz and Galvin1999 Algoritmo do Banco (Cont.) • • Notação < significa ordem numérica da seqüência (ficha #, processo #) – (a,b) < (c,d) if a < c or if a = c and b < d – max (a0,…, an-1) é um elemento k, tal que k ai for i = 0, …, n – 1 Dados compartilhados var choosing: array [0..n – 1] of boolean; number: array [0..n – 1] of integer, inicializados para false e 0 respectivamente Operating System Concepts 6.12 Silberschatz and Galvin1999 Algoritmo de Banco(Cont.) repeat choosing[i] := true; number[i] := max(number[0], number[1], …, 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; seção crítica number[i] := 0; seção restante until false; Operating System Concepts 6.13 Silberschatz and Galvin1999 Hardware de Sincronização • Testa e modifica o conteúdo de uma palavra atomicamente function Test-and-Set (var target: boolean): boolean; begin Test-and-Set := target; target := true; end; Operating System Concepts 6.14 Silberschatz and Galvin1999 Exclusão mútua com Test-and-Set • • Dado compartilhado: var lock: boolean (initially false) Processo Pi repeat while Test-and-Set (lock) do no-op; seção crítica lock := false; seção restante until false; Operating System Concepts 6.15 Silberschatz and Galvin1999 Semáforo • • • Um mecanismo de sincronização que nao implica em espera ocupada (busy waiting). Semáforo S – variável inteira pode ser acessado somente através de duas operações indivisíveis (atômicas) wait (S): while S 0 do no-op; S := S – 1; signal (S): S := S + 1; Operating System Concepts 6.16 Silberschatz and Galvin1999 Exemplo: Seção crítica de n processos • • Variáveis compartilhadas – var mutex : semaphore – inicialmente mutex = 1 Processo Pi repeat wait(mutex); seção crítica signal(mutex); seção restante until false; Operating System Concepts 6.17 Silberschatz and Galvin1999 Implementação de semáforo • Define um semáforo como estrutura (record) type semaphore = record value: integer L: list of process; end; • Suponha duas operações simples: – block suspende o processo que a executa – wakeup(P) recomeça a execução do processo P. Operating System Concepts 6.18 Silberschatz and Galvin1999 Implementação de semáforos (Cont.) • Operações em cima de semáforos agora são definidas assim: wait(S): S.value := S.value – 1; if S.value < 0 then begin add this process to S.L; block; end; signal(S): S.value := S.value + 1; if S.value 0 then begin remove a process P from S.L; wakeup(P); end; Operating System Concepts 6.19 Silberschatz and Galvin1999 O semáforo como mecanismo geral de sincronização • • • Execute B in Pj only after A executed in Pi Use semaphore flag initialized to 0 Code: Operating System Concepts Pi Pj A wait(flag) signal(flag) B 6.20 Silberschatz and Galvin1999 Deadlock and Starvation • • • Deadlock – dois ou mais processos esperam indefinitamente por um evento que pode ser causado somente por um dos processos em espera. S e Q sejam dois semáforos inicializados em 1 P0 P1 wait(S); wait(Q); wait(Q); wait(S); signal(S); signal(Q); signal(Q) signal(S); Starvation – bloqueio sem fim. Um processo nunca é removido da fila de semáforo na qual ele fica bloqueado. Operating System Concepts 6.21 Silberschatz and Galvin1999 Dois Tipos de Semáforos • Semáforo contábil – valor inteiro que se pode estender até o infinito. • Semáforo binário – valor pode ser somente 0 ou 1; mais facil de implementar. • É possível implementar semáforo contábil a partir de semáforos binários. Operating System Concepts 6.22 Silberschatz and Galvin1999 Implementando S com semáforos binários • • Estruturas de dados: var S1: binary-semaphore; S2: binary-semaphore; S3: binary-semaphore; C: integer; Initialização: S1 = S3 = 1 S2 = 0 C = valor inicial do semáforo S Operating System Concepts 6.23 Silberschatz and Galvin1999 Implementando S (Cont.) • • wait operation wait(S3); wait(S1); C := C – 1; if C < 0 then begin signal(S1); wait(S2); end else signal(S1); signal(S3); signal operation wait(S1); C := C + 1; if C 0 then signal(S2); signal(S1); Operating System Concepts 6.24 Silberschatz and Galvin1999 Problemas clássicos de Sincronização • • • Problema do buffer limitado Problema de Escritores e Leitores Problema dos filósofos jantando Operating System Concepts 6.25 Silberschatz and Galvin1999 Problema do Buffer limitado • Dados compartilhados type item = … var buffer = … full, empty, mutex: semaphore; nextp, nextc: item; full :=0; empty := n; mutex :=1; Operating System Concepts 6.26 Silberschatz and Galvin1999 Bounded-Buffer Problem (Cont.) • Processo produtor repeat … produza um item em nextp … wait(empty); wait(mutex); … coloque o item em nextp no buffer … signal(mutex); signal(full); until false; Operating System Concepts 6.27 Silberschatz and Galvin1999 Bounded-Buffer Problem (Cont.) • Processo consumidor repeat wait(full) wait(mutex); … remove um item do buffer para nextc … signal(mutex); signal(empty); … consume o item em nextc … until false; Operating System Concepts 6.28 Silberschatz and Galvin1999 Readers-Writers Problem • • Dados compartilhados var mutex, wrt: semaphore (=1); readcount : integer (=0); processo escritor wait(wrt); … escrevendo … signal(wrt); Operating System Concepts 6.29 Silberschatz and Galvin1999 Readers-Writers Problem (Cont.) • Process leitor wait(mutex); readcount := readcount +1; if readcount = 1 then wait(wrt); signal(mutex); … reading is performed … wait(mutex); readcount := readcount – 1; if readcount = 0 then signal(wrt); signal(mutex): Operating System Concepts 6.30 Silberschatz and Galvin1999 Problema dos filósofos jantando • Dados compartilhados var chopstick: array [0..4] of semaphore; (=1 initially) Operating System Concepts 6.31 Silberschatz and Galvin1999 Dining-Philosophers Problem (Cont.) • Filósofo i: repeat wait(chopstick[i]) wait(chopstick[i+1 mod 5]) … come … signal(chopstick[i]); signal(chopstick[i+1 mod 5]); … pensa … until false; Operating System Concepts 6.32 Silberschatz and Galvin1999 Regiões críticas • • Uma construção de alto nível Uma variável v do tipo T é declarada assim: var v: shared T • a variável v é acessado somente dentro de uma construção do tipo region v when B do S na qual B é uma expressão booleana. Enquanto a instrução (o bloco de instruções) S é executado, nenhum outro processo pode acessar a variável v. Operating System Concepts 6.33 Silberschatz and Galvin1999 Regiões críticas (Cont.) • • Regiões que se referem aos mesmos variáveis excluem uma à outra no tempo. Quando um processo executa uma construção region, a expressão booleana B é avaliada. Se B é verdade, a instrução S é executada. Se é falso, o processo fica bloqueado até que B passa a ser verdade e nenhum outro processo está na região associada com v. Operating System Concepts 6.34 Silberschatz and Galvin1999 Exemplo – Buffer limitado • Variáveis compartilhadas: var buffer: shared record pool: array [0..n–1] of item; count,in,out: integer end; • Processo produtor region buffer when count < n do begin pool[in] := nextp; in:= in+1 mod n; count := count + 1; end; Operating System Concepts 6.35 Silberschatz and Galvin1999 Exemplo – Buffer limitado (Cont.) • Processo consumidor region buffer when count > 0 do begin nextc := pool[out]; out := out+1 mod n; count := count – 1; end; Operating System Concepts 6.36 Silberschatz and Galvin1999 Implementação: region x when B do S • Associate with the shared variable x, the following variables: var mutex, first-delay, second-delay: semaphore; first-count, second-count: integer, • • Mutually exclusive access to the critical section is provided by mutex. If a process cannot enter the critical section because the Boolean expression B is false, it initially waits on the first-delay semaphore; moved to the second-delay semaphore before it is allowed to reevaluate B. Operating System Concepts 6.37 Silberschatz and Galvin1999 Implementation (Cont.) • • • Keep track of the number of processes waiting on first-delay and second-delay, with first-count and second-count respectively. The algorithm assumes a FIFO ordering in the queuing of processes for a semaphore. For an arbitrary queuing discipline, a more complicated implementation is required. Operating System Concepts 6.38 Silberschatz and Galvin1999 wait(mutex); while not B do begin first-count := first-count + 1; if second-count > 0 then signal(second-delay) else signal(mutex); wait(first-delay): first-count := first-count – 1; if first-count > 0 then signal(first-delay) else signal(second-delay); wait(second-delay); second-count := second-count – 1; end; S; if first-count >0 then signal(first-delay); else if second-count >0 then signal(second-delay); else signal(mutex); Operating System Concepts 6.39 Silberschatz and Galvin1999 Monitors • High-level synchronization construct that allows the safe sharing of an abstract data type among concurrent processes. type monitor-name = monitor variable declarations procedure entry P1 :(…); begin … end; procedure entry P2(…); begin … end; procedure entry Pn (…); begin…end; begin initialization code end Operating System Concepts 6.40 Silberschatz and Galvin1999 Monitors (Cont.) • To allow a process to wait within the monitor, a condition variable must be declared, as var x, y: condition • Condition variable can only be used with the operations wait and signal. – The operation x.wait; means that the process invoking this opeation is suspended until another process invokes x.signal; – The x.signal operation resumes exactly one suspended process. If no process is suspended, then the signal operation has no effect. Operating System Concepts 6.41 Silberschatz and Galvin1999 Schematic view of a monitor Operating System Concepts 6.42 Silberschatz and Galvin1999 Monitor with condition variables Operating System Concepts 6.43 Silberschatz and Galvin1999 Dining Philosophers Example type dining-philosophers = monitor var state : array [0..4] of :(thinking, hungry, eating); var self : array [0..4] of condition; procedure entry pickup (i: 0..4); begin state[i] := hungry, test (i); if state[i] eating then self[i], wait, end; procedure entry putdown (i: 0..4); begin state[i] := thinking; test (i+4 mod 5); test (i+1 mod 5); end; Operating System Concepts 6.44 Silberschatz and Galvin1999 Dining Philosophers (Cont.) procedure test(k: 0..4); begin if state[k+4 mod 5] eating and state[k] = hungry and state[k+1 mod 5] ] eating then begin state[k] := eating; self[k].signal; end; end; begin for i := 0 to 4 do state[i] := thinking; end. Operating System Concepts 6.45 Silberschatz and Galvin1999 Monitor Implementation Using Semaphores • Variables var mutex: semaphore (init = 1) next: semaphore (init = 0) next-count: integer (init = 0) • • Each external procedure F will be replaced by wait(mutex); … body of F; … if next-count > 0 then signal(next) else signal(mutex); Mutual exclusion within a monitor is ensured. Operating System Concepts 6.46 Silberschatz and Galvin1999 Monitor Implementation (Cont.) • • For each condition variable x, we have: var x-sem: semaphore (init = 0) x-count: integer (init = 0) The operation x.wait can be implemented as: x-count := x-count + 1; if next-count >0 then signal(next) else signal(mutex); wait(x-sem); x-count := x-count – 1; Operating System Concepts 6.47 Silberschatz and Galvin1999 Monitor Implementation (Cont.) • The operation x.signal can be implemented as: if x-count > 0 then begin next-count := next-count + 1; signal(x-sem); wait(next); next-count := next-count – 1; end; Operating System Concepts 6.48 Silberschatz and Galvin1999 Monitor Implementation (Cont.) • • Conditional-wait construct: x.wait(c); – c – integer expression evaluated when the wait opertion is executed. – value of c (priority number) stored with the name of the process that is suspended. – when x.signal is executed, process with smallest associated priority number is resumed next. Check tow conditions to establish correctness of system: – User processes must always make their calls on the monitor in a correct sequence. – Must ensure that an uncooperative process does not ignore the mutual-exclusion gateway provided by the monitor, and try to access the shared resource directly, without using the access protocols. Operating System Concepts 6.49 Silberschatz and Galvin1999 Solaris 2 Operating System • • • Implements a variety of locks to support multitasking, multithreading (including real-time threads), and multiprocessing. Uses adaptive mutexes for efficiency when protecting data from short code segments. Uses condition variables and readers-writers locks when longer sections of code need access to data. Operating System Concepts 6.50 Silberschatz and Galvin1999