tastyminerals
tastyminerals

Reputation: 6548

How to increment class field within a Thread in python?

I am trying to implement a small garden example. Garden is a class that has grow() function, which checks the amount of water supplied every second. When the amount of water is more than some threshold, garden produces a few flowers.

Here is my first try:

Garden class

import time

class Garden:
    def __init__(self):
        self.water = 0
        print("Garden built!")

    def grow(self):
        while self.water < 50:
            print("Water supplied: {0}".format(self.water))
            time.sleep(1)
        print("Produced 5 flowers!")

main.py

import time
from garden import Garden
from threading import Thread
from queue import Queue

def main():
    que = Queue()
    garden = Garden()
    thr = Thread(target=garden.grow).start()
    que_garden = que.get()
    water(que_garden, 20)
    time.sleep(5)
    water(que_garden, 30)
    thr.join()

def water(garden, amount):
    garden.water += amount
    print("Watered with {0}!".format(amount))

When I run main.py I get the following input:

Garden built!
Water supplied: 0
Water supplied: 0
Water supplied: 0
Water supplied: 0
Water supplied: 0

So, grow() gets constantly called and never gets to water(que_garden, 20) line. I expected that once thr = Thread(target=garden.grow).start() is called it is not locked until grow() finishes but continues to the next line. What am I missing here?

Upvotes: 1

Views: 51

Answers (3)

Mike M&#252;ller
Mike M&#252;ller

Reputation: 85582

This:

que_garden = que.get()

blocks until there is something in the queue. But there is no que_garden.put() anywhere.

This works without a queue:

import time
from garden import Garden
from threading import Thread

def main():
    garden = Garden()
    thr = Thread(target=garden.grow)
    thr.start()
    water(garden, 20)
    time.sleep(5)
    water(garden, 30)
    time.sleep(5)
    water(garden, 10)
    thr.join()

def water(garden, amount):
    garden.water += amount
    print("Watered with {0}!".format(amount))

main()

Output:

Garden built!
Water supplied: 0
Watered with 20!
Water supplied: 20
Water supplied: 20
Water supplied: 20
Water supplied: 20
Watered with 30!
Produced 5 flowers!
Watered with 10!

Upvotes: 1

Iron Fist
Iron Fist

Reputation: 10961

From Python Documentation:

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
This constructor should always be called with keyword arguments. Arguments are:

group should be None; reserved for future extension when a ThreadGroup class is implemented.

target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.

So, Change:

thr = Thread(target=garden.grow()).start()

to

thr = Thread(target=garden.grow).start()

Upvotes: 0

D.Shawley
D.Shawley

Reputation: 59623

I think that you want garden.grow instead of garden.grow(). The target parameter is a callable. You are calling the grow method and passing its return value.

Upvotes: 1

Related Questions