how to exactly use sleep and wakeup in python3? (multithread)

1

Hello, I'm trying to make the famous producer / consumer problem in python3, transcribing it from my OS book, but I've been experiencing a problem, apparently wait () or something like that, because simply after the first time the threads run loose. code:

# -*- coding: utf-8 -*-
import threading
acordar_dormir_produtor = threading.Event()
acordar_dormir_consumidor = threading.Event()
bufer = 0
bufer_max = 10


def consumidor():
    global acordar_dormir_produtor
    global acordar_dormir_consumidor
    global bufer
    global bufer_max
    while True:
        if bufer == 0:
            print ("consumidor dormindo")
            acordar_dormir_consumidor.wait()
            print ("consumidor acordou")
        bufer = bufer - 1
        if bufer == (bufer_max - 1):
            print ("distracando produtor")
            acordar_dormir_produtor.set()
            acordar_dormir_produtor.clear()
        print ("consumidor",bufer)


def produtor():
    global acordar_dormir_produtor
    global acordar_dormir_consumidor
    global bufer
    global bufer_max
    while True:
        if bufer == bufer_max:
            print ("produtor dormindo")
            acordar_dormir_produtor.wait()
            print ("produtor acordou")
        bufer = bufer + 1
        if bufer == 1:
            print ("distracando consumidor")
            acordar_dormir_consumidor.set()
            acordar_dormir_produtor.clear()
        print ("produtor ",bufer)
print (bufer)
b = threading.Thread(target=produtor)
a = threading.Thread(target=consumidor)
a.start()
b.start()
#while True:
   # time.sleep(3)
   # print (bufer)

How to do this? has another object since Event does not work? I tried the conditions without success (actually did not even execute)

    
asked by anonymous 02.07.2015 / 01:25

2 answers

1

Using a Queue as drgarcia suggests is a higher level solution to a real problem.

Your situation however is didactic - and here is what I think is going wrong: you call set and clear of Event next to each other. The implementation of Python threading is not something that uses event signing - before it is done by polling - that is, from time to time execution will pass to the thread that is waiting on a event.wait and see if its state has changed - but this check is not automatically triggered by the call to Event.set - then you would have to give a lot (but a lot of luck) for the thread to be called exactly between your call to set and call to clear .

For what you've done, put the call to clear immediately before of the call to wait on the thread that will wait (not on the thread that will send the set ):

...
def consumidor():
   ...
   acordar_dormir_consumidor.clear()      
   acordar_dormir_consumidor.wait()

...
def produtor():
    ...
    acordar_dormir_consumidor.set()
    
02.07.2015 / 14:59
0

You can use the Thread class and the Queue class (which is thread safe). For sleeping you can use time.sleep .

# -*- coding: utf-8 -*-
from threading import Thread
import time
import random
from queue import Queue


queue = Queue(10)


class ProducerThread(Thread):
    def run(self):
        nums = range(5)
        global queue
        while True:
            num = random.choice(nums)
            queue.put(num)
            print("Produced", num)
            time.sleep(random.random())


class ConsumerThread(Thread):
    def run(self):
        global queue
        while True:
            num = queue.get()
            queue.task_done()
            print("Consumed", num)
            time.sleep(random.random())


ProducerThread().start()
ConsumerThread().start()
The Producer feeds the buffer in the Queue.put() method while the Consumer reads the buffer through the Queue.get() method (and signals that the buffer reading was successful using the Queue.task_done() method). After each one does its task, it "sleeps" for a random time.

The Queue.get() method waits for a value in the queue, so regardless of who gets to work first, the consumer will only follow up when there is something in the queue to be a consumer.

If the example needs to be more didactic, you can use the threading.Condition class:

# -*- coding: utf-8 -*-
from threading import Thread, Condition
import time
import random


queue = []
MAX_NUM = 10
condition = Condition()


class ProducerThread(Thread):
    def run(self):
        nums = range(5)
        global queue
        while True:
            condition.acquire()
            if len(queue) == MAX_NUM:
                print("Queue full, producer is waiting")
                condition.wait()
                print("Space in queue, Consumer notified the producer")
            num = random.choice(nums)
            queue.append(num)
            print("Produced", num)
            condition.notify()
            condition.release()
            time.sleep(random.random())


class ConsumerThread(Thread):
    def run(self):
        global queue
        while True:
            condition.acquire()
            if not queue:
                print("Nothing in queue, consumer is waiting")
                condition.wait()
                print("Producer added something to queue and notified the consumer")
            num = queue.pop(0)
            print("Consumed", num)
            condition.notify()
            condition.release()
            time.sleep(random.random())


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

With condition you can lock to control when the consumer and the producer should wait and when they should work.

Being objective in answering your question, condition.wait() causes the thread to sleep waiting for the condition.notify() that works like wakeup.

Reference: link

    
02.07.2015 / 03:51