This is my python module that is being ran as two threads in main. One thread runs monitor_wind()
which adds to wind_count
every spin and another thread runs calculate_speed()
to get wind in mph from the count, and add it to a list that is later averaged for average wind in mph.
My problem is that calculate_speed()
doesn't seem to be accessing the global variable wind_count
, it is always 0 even when monitor_wind()
is adding to. But the changes it makes to wind_list
can be seen in the globals()
list.
How can I get it to access the global variable?
from gpiozero import Button
import math
from time import sleep
wind_sensor = Button(6)
wind_count = 0
wind_list = []
def calculate_speed():
while True:
global wind_list, wind_count
print(wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
wind_list.append(speed)
wind_count = 0 # Reset wind count
sleep(5)
def spin():
global wind_count
wind_count += 1
def monitor_wind():
wind_sensor.when_pressed = spin
To me, this does not appear to be an issue with your use of globals, though I would discourage using globals, and instead make a class WindMonitor
. You should also use a lock if you are accessing a variable from multiple threads.
Try this out (I had to call spin on random time intervals because I don't have gpios on my device).
wspeed.py
# from gpiozero import Button
import math
import random
import threading
from time import sleep
DEFAULT_WIND_SENSOR = None; # Button(6)
class WindMonitor:
def __init__(self, button=DEFAULT_WIND_SENSOR):
self.wind_count = 0
self.wind_list = []
self.button = button
self.wind_count_lock = threading.Lock()
def calculate_speed(self, stop_event):
while True:
with self.wind_count_lock:
print(self.wind_count)
radius_cm = 9.0
cm_in_mile = 160934.4
circumference_cm = (2 * math.pi) * radius_cm
rotations = self.wind_count / 2.0
dist_miles = (circumference_cm * rotations) / cm_in_mile
speed = dist_miles / 5 # Divide distance by time, 5 seconds
print(speed)
self.wind_list.append(speed)
self.wind_count = 0 # Reset wind count
if stop_event.wait(5):
return
def spin(self):
with self.wind_count_lock:
self.wind_count += 1
def monitor_wind(self):
# self.button.when_pressed = self.spin
while True:
sleep(float(random.randint(1, 10)) / 10)
self.spin()
__main__.py
import threading as th
import time
from wspeed import WindMonitor
if __name__ == '__main__':
monitor = WindMonitor()
stop_event = th.Event()
th_wmonitor = th.Thread(target=monitor.monitor_wind, daemon=True)
th_wspeed = th.Thread(target=monitor.calculate_speed, args=[stop_event], daemon=True)
try:
th_wspeed.start()
th_wmonitor.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
stop_event.set()
Edit: Explaining stop event
All of your threads loop forever (main thread, th_wmonitor
, and th_wspeed
). You want the program to exit when the main terminates.
When python exits, it waits for all non-daemonic threads to terminate, so you did the right thing by making them daemonic. The problem is that python will only exit when there is a single remaining daemonic thread. Because both daemonic threads loop infinitely, you need a way to tell one (or both) of them to when the program exits.
The simplest way of achieving this is to use a threading.Event
object. An Event
is a simple way of communicating between threads. It's basically a flag that you set in one thread and check in another. By having an exception in main, you can set the stop_event
instance of threading.Event
. This lets any thread with access to stop_event
that the main thread has exited, and other threads may terminate when they are ready to terminate.
The th_wspeed
needs to terminate at a specific time because you don't want to terminate in the middle of a print statement. For that reason, I made th_wspeed
the one to check stop_event
. When th_wspeed
sees stop_event
has been set, it returns, thus terminating one of the two daemonic threads. At that point, because python sees that only one daemonic thread remains, it will force that thread to terminate, and the program exits.
Without the stop event, the program would not terminate when you, for example, press CTRL+C.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.