Mutua Esclusione e Threading

In questa lezione abbiamo visto come l'uso dei thread porti ad aver bisogno di accedere ai dati in modo esclusivo e di sincronizzare i thread. Per questo, abbiamo introdotto eventi, lock e condition variables.

Inoltre, abbiamo introdotto i concetti di pila, coda e lista che approfondiremo nelle prossime lezioni.

Trovate in fondo alla pagina i due esempi di codice visti a lezione.

Threading and Mutual Exclusion

In this lecture we have shown how threading leads to a need for mutual exclusion in data accesses and thread synchronization. To this end, we have introduced events, locks and condition variables.

Producer and Consumers

#!/usr/bin/python
 
from threading import Thread, Lock, currentThread, enumerate, Event, Condition,
activeCount
from random import randint, choice
 
outputLock = Lock()
endThreads = Event()
 
class Buffer :
        def __init__(self):
                self.data = []
                self.lock= Condition()
 
        def enqueue(self,datum):
                self.lock.acquire()
                self.data.append(datum)
                self.lock.notify()
                self.lock.release()
 
        def dequeue(self):
                self.lock.acquire()
                if not len(self.data) : self.lock.wait()
                datum=self.data.pop()
                self.lock.release()
                return datum
 
        def notify_end(self):
                self.lock.acquire()
                self.lock.notifyAll()
                self.lock.release()
 
        def __len__(self):
                return len(self.data)
 
 
class BufferUser(Thread):
        def __init__(self, buffer):
                Thread.__init__(self)
                self.buffer=buffer
 
 
class Consumer(BufferUser):
        def run(self):
                while not endThreads.isSet() :
                        datum = self.buffer.dequeue()
                        outputLock.acquire()
                        print currentThread(), datum
                        outputLock.release()
                print 'Ending', currentThread()
 
class Producer(BufferUser):
        def run(self):
                while not endThreads.isSet() :
                        datum = currentThread(), randint(1,100)
                        self.buffer.enqueue(datum)
                print 'Ending', currentThread()
 
 
buffers = [ Buffer() for i in range(3) ]
 
class Manager(Thread):
        def run(self):
                raw_input("Stop the system...")
                outputLock.acquire()
                threads = enumerate()
                print 'Active Threads:', threads
                endThreads.set()
                for b in buffers :
                        b.notify_end()
                outputLock.release()
 
for t in range(3):
        Producer(choice(buffers)).start()
        Consumer(choice(buffers)).start()
Manager().start()
for t in enumerate() :
        if t!=currentThread():
                t.join()
print 'All threads killed!'
print 'Buffers entry remaining:',
for b in buffers :
        print len(b),
print ''

Barber's Problem

#!/usr/bin/python
 
from threading import Thread, Lock, currentThread, enumerate, Event, Condition, activeCount
from random import randint, choice
from time import sleep
 
endThreads = Event()
 
class BarberShop :
        def __init__(self,nchairs):
                self.nchairs = nchairs
                self.busychairs = []
                self.lock = Condition()
 
        def sit(self):
                self.lock.acquire()
                if len(self.busychairs)>=self.nchairs : self.lock.wait()
                event = Event()
                self.busychairs.append(event)
                self.lock.release()
                event.wait()
 
        def cut(self):
                self.lock.acquire()
                event = self.busychairs.pop()
                self.lock.notify()
                self.lock.release()
                sleep(randint(0,3))
                event.set()
 
        def notify_end(self):
                self.lock.acquire()
                self.lock.notifyAll()
                self.lock.release()
 
        def busy(self):
                return len(self.busychairs)>0
 
class BarberShopUser(Thread):
        def __init__(self, shop):
                Thread.__init__(self)
                self.shop=shop
 
class Barber(BarberShopUser):
        def run(self):
                while not endThreads.isSet() :
                        if self.shop.busy() :
                                print 'Barber', currentThread(), 'working!'
                                self.shop.cut()
                        else :
                                print 'Barber', currentThread(), 'sleeping!'
                                sleep(randint(0,3))
                print 'Ending', currentThread()
 
class Customer(BarberShopUser):
        def run(self):
                print 'Customer', currentThread(), 'entering barber shop!'
                self.shop.sit()
                print 'Customer', currentThread(), 'served!'
 
barbershop=BarberShop(4)
 
class Manager(Thread):
        def run(self):
                raw_input("Stop the system...")
                threads = enumerate()
                print 'Active Threads:', threads
                endThreads.set()
                barbershop.notify_end()
 
for t in range(2):
        Barber(barbershop).start()
Manager().start()
for t in range(15):
        sleep(randint(0,2))
        Customer(barbershop).start()
 
for t in enumerate() :
        if t!=currentThread():
                t.join()
print 'All threads killed!'