Producent a konzument

Užitečné odkazy

Objekt Condition

Podmínka je vždy asociována s nějakým druhem zámku. Podmínce může být zámek předán, případně si vytvoří zámek svůj. Již známe metody acquire() a release() jsou předány zámku v objektu Condition.

Novinkou však jsou metody wait() a notify(). Metoda wait() uvolní zámek a čeká dokud jej jiné vlákno nepotvrdí metodou notify(), nebo notify_all() a poté zámek zamče.

Metody notify() a notify_all() neuvolňují zámek. To znamená, že probuzené vlákno okamžitě nevysoupí ze svého volání wait(), ale počká až se vlákno které volalo notify() vzdá vlastnictví zámku.

Condition je většinou používán následovně:

1
2
3
4
5
6
7
8
9
10
# Consume one item
with cv:
    while not an_item_is_available():
        cv.wait()
    get_an_available_item()

# Produce one item
with cv:
    make_an_item_available()
    cv.notify()

Producent a konzument

V následující implementaci dochází k problému konzumace prázdné fronty.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from threading import Thread, Lock
import time
import random

queue = []
lock = Lock()

class ProducerThread(Thread):
    def run(self):
        # Vytvoreni seznamu [0, 1, 2, 3, 4]
        nums = range(5) 
        
        # Umozneni zapisu do globalni promenne (append)
        global queue
        
        for _ in range(10):
            # Vyber nahodneho cisla z [0, 1, 2, 3, 4]
            num = random.choice(nums) 
            
            with lock:
                queue.append(num)
                print("Produced {}".format(num))
            
            time.sleep(random.random())


class ConsumerThread(Thread):
    def run(self):
        # Umozneni zapisu do globalni promenne (pop)
        global queue
        
        for _ in range(10):
            with lock:
                # Demonstrace problemu, pop na prazdnou frontu
                # Konzument by mel cekat
                if not queue:
                    print("Nothing in queue, but consumer will try to consume")

                num = queue.pop(0)
                print("Consumed {}".format(num))
            
            time.sleep(random.random())


ProducerThread().start()
ConsumerThread().start()

Úkol
Předchozí kód upravte za pomoci Condition tak, aby nedocházelo ke konzumaci prázdné fronty. Pokud ve frontě nebude žádné číslo, konzument musí čekat.

Úkol
Upravte úkol tak aby velikost fronty byla omezena. Například na délku 5 hodnot ve frontě. K řešení využíjte Condition.