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. Toto je důležité pokud více podmínek používá stejný zámek. 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
47
48
49
50
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

        while True:
            # Vyber nahodneho cisla z [0, 1, 2, 3, 4]
            num = random.choice(nums)

            lock.acquire()
            queue.append(num)
            print("Produced {}".format(num))
            lock.release()

            time.sleep(random.random())


class ConsumerThread(Thread):
    def run(self):

        # Umozneni zapisu do globalni promenne (pop)
        global queue

        while True:
            lock.acquire()

            # 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))
            lock.release()

            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.