Receita: SemaforosDeadlock
Abaixo estão pequenos exemplos do uso de semáforos e como não deixar ocorrer deadlock.
Esses códigos criei para demonstrar os conceitos básicos, para a utilização em um curso de Sistemas Operacionais.
Semáforos para cuidar da Seção Crítica de um Programa
1 # -*- coding: ISO-8859-1 -*-
2
3 import thread
4 import time, random
5
6 s = thread.allocate_lock()
7
8 def tempo(i):
9 t = random.randint(3,7)
10 print "Processo %i dormindo por %i" %(i, t)
11 time.sleep(t)
12
13 def thread1():
14 while True:
15 print "Processo 1 - Adquirindo semáforo"
16 s.acquire()
17 print "Processo 1 - Seção crítica"
18 tempo(1)
19 print "Processo 1 - Liberando semáforo"
20 s.release()
21 print "Processo 1 - seção não crítica"
22 tempo(1)
23
24 def thread2():
25 while True:
26 print "Processo 2 - Adquirindo semáforo"
27 s.acquire()
28 print "Processo 2 - Seção crítica"
29 tempo(2)
30 print "Processo 2 - Liberando semáforo"
31 s.release()
32 print "Processo 2 - seção não crítica"
33 tempo(2)
34
35 thread.start_new_thread(thread1, ())
36 thread.start_new_thread(thread2, ())
37
38 while 1: pass
O programa acima é funcional, mas pode ocorrer travamentos devido a tentativas de acessos simultâneos aos recursos.
Deadlock com Semáforos
1 # -*- coding: ISO-8859-1 -*-
2
3 import thread
4 import time, random
5
6 s1 = thread.allocate_lock()
7 s2 = thread.allocate_lock()
8
9 def tempo(i):
10 t = random.randint(1,5)
11 print "Processo %i dormindo por %i" %(i, t)
12 time.sleep(t)
13
14 def thread1():
15 print "Processo 1 - Adquirindo semáforo S1"
16 s1.acquire()
17 time.sleep(1)
18 print "Processo 1 - Adquirindo semáforo S2"
19 s2.acquire()
20 print "Processo 1 - Seção crítica"
21 tempo(1)
22 print "Processo 1 - Liberando semáforos"
23 s1.release()
24 s2.release()
25 print "Processo 1 - seção não crítica"
26 tempo(1)
27
28 def thread2():
29 print "Processo 2 - Adquirindo semáforo S2"
30 s2.acquire()
31 time.sleep(1)
32 print "Processo 2 - Adquirindo semáforo S1"
33 s1.acquire()
34 print "Processo 2 - Seção crítica"
35 tempo(2)
36 print "Processo 2 - Liberando semáforos"
37 s2.release()
38 s1.release()
39 print "Processo 2 - seção não crítica"
40 tempo(2)
41
42 thread.start_new_thread(thread1, ())
43 thread.start_new_thread(thread2, ())
44
45 while 1: pass
Problemas Clássicos de Sincronismo
Buffer Limitado
1 # -*- coding: ISO-8859-1 -*-
2 import thread
3 import time, random
4 import threading
5
6 class BufferLimitado:
7 TAM_BUFFER = 5
8 mutex = threading.Semaphore(1)
9 empty = threading.Semaphore(TAM_BUFFER)
10 full = threading.Semaphore(0)
11 buffer = range(TAM_BUFFER)
12 cheio = 0
13 livre = 0
14
15 def insert(self, item):
16 self.empty.acquire()
17 self.mutex.acquire()
18 self.buffer[self.livre] = item
19 self.livre = (self.livre + 1) % self.TAM_BUFFER
20 self.mutex.release()
21 self.full.release()
22
23 def remove(self):
24 self.full.acquire()
25 self.mutex.acquire()
26 item = self.buffer[self.cheio]
27 self.cheio = (self.cheio + 1) % self.TAM_BUFFER
28 self.mutex.release()
29 self.empty.release()
30 return item
31
32 b = BufferLimitado()
33
34 def produtor():
35 while True:
36 time.sleep(random.randint(1, 10) / 100.0)
37 item = time.ctime()
38 b.insert(item)
39 print "Produtor produziu:", item, b.livre, b.cheio
40
41 def consumidor():
42 while True:
43 time.sleep(random.randint(1, 10) / 100.0)
44 item = b.remove()
45 print "Consumidor consumiu:", item, b.livre, b.cheio
46
47 thread.start_new_thread(produtor, ())
48 thread.start_new_thread(consumidor, ())
49
50 while 1: pass
Leitores-Escritores
1 # -*- coding: ISO-8859-1 -*-
2 import thread
3 import time, random
4 import threading
5
6 class BancoDados:
7 contLeitor = 0
8 mutex = threading.Semaphore(1)
9 bd = threading.Semaphore(1)
10
11 def acquireReadLock(self):
12 global contLeitor
13 self.mutex.acquire()
14 self.contLeitor += 1
15
16 # É o primeiro leitor?
17 if self.contLeitor == 1:
18 self.bd.acquire()
19
20 self.mutex.release()
21
22 def releaseReadLock(self):
23 global contLeitor
24 self.mutex.acquire()
25 self.contLeitor -= 1
26
27 # É o último leitor?
28 if self.contLeitor == 0:
29 self.bd.release()
30
31 self.mutex.release()
32
33 def acquireWriteLock(self):
34 self.bd.acquire()
35
36 def releaseWriteLock(self):
37 self.bd.release()
38
39 bd = BancoDados()
40
41 def escritor(e):
42 while True:
43 time.sleep(random.randint(1, 5))
44 bd.acquireWriteLock()
45 print "Escritor %i - escrevendo..." %e
46 time.sleep(random.randint(1, 5))
47 bd.releaseWriteLock()
48 print "Escritor %i - parou de escrever." %e
49
50 def leitor(l):
51 while True:
52 time.sleep(random.randint(1, 10))
53 bd.acquireReadLock()
54 print "Leitor %i - lendo..." %l
55 time.sleep(random.randint(1, 5))
56 bd.releaseReadLock()
57 print "Leitor %i - parou de ler." %l
58
59 for i in range(2):
60 print "Escritor", i
61 thread.start_new_thread(escritor, tuple([i]))
62 for i in range(3):
63 print "Leitor", i
64 thread.start_new_thread(leitor, tuple([i]))
65
66
67 while 1: pass
Filósofos na Mesa de Jantar
1 # -*- coding: ISO-8859-1 -*-
2 import thread
3 import time, random
4 import threading
5
6 garfo = list()
7 for i in range(5):
8 garfo.append(threading.Semaphore(1))
9
10 def filosofo(f):
11 f = int(f)
12 while True:
13 # garfo da esquerda
14 garfo[f].acquire()
15 # garfo da direita
16 garfo[(f + 1) % 5].acquire()
17 print "Filósofo %i comendo..." %f
18 time.sleep(random.randint(1, 5))
19 garfo[f].release()
20 garfo[(f + 1) % 5].release()
21 print "Filósofo %i pensando..." %f
22 time.sleep(random.randint(1, 10))
23
24 for i in range(5):
25 print "Filósofo", i
26 thread.start_new_thread(filosofo, tuple([i]))
27
28 while 1: pass
Volta para CookBook.