python multithreading - confused with output - python

I am trying to create a multithreading program that will run one thread for three seconds, then 'pause' the thread using event objects, wait for a few seconds, then repeat the process over again. here is my code:
import threading
import time
counter = 1
def control():
global counter
test_event.wait()
while(test_event.is_set()):
print 'waiting 3 seconds'
time.sleep(3)
event.set()
time.sleep(3)
event.clear()
if(counter == 1):
counter = counter - 1
def function():
global counter
event.wait()
while (event.is_set()):
test_event.clear()
print 'event is set to high'
time.sleep(1)
print 'event is set to low'
test_event.set()
event = threading.Event()
test_event = threading.Event()
t1 = threading.Thread(target = control)
t2 = threading.Thread(target = function)
t1.start()
t2.start()
while(counter == 1):
test_event.set()
the output I am desiring should look like this:
waiting 3 seconds
event is set to high
event is set to high
event is set to high
event is set to low
waiting 3 seconds
event is set to high
....
....
and that keeps repeating.
the output I am currently receiving however is this:
waiting three seconds
event is set to high
event is set to high
event is set to high
waiting 3 seconds
event is set to low
waiting 3 seconds
waiting 3 seconds
waiting 3 seconds
...
...
and that keeps repeating.
Can anybody detect where I am messing up, and possibly offer any advice for me to fix? I cannot seem to figure out what I am doing wrong.
P.S. I am aware that this code probably is constructed very poorly, but I am completely new to multithreading...sorry in advance!

Related

Logging rainfall with Python

First post and I am at a dead end with this problem.
(some background)
I have a raspberry PiZero which I am developing a weather station with, so far it logs temp, humidity and pressure as well as sending the data to the windy.com API. Recently I added a tipping bucket rain gauge.
This has 2 wires which connect to the GPIO, when the bucket tips it momentarily competes the circuit, essentially a button press!
The goal here is to count the tips every hour, then reset. before resetting, send this data to log file + Windy API. This is the part I am struggling with.
I am pretty good with python but I am at a true writers block moment, here is a small program I cobbled together from snippets which counts the tips for testing
/usr/bin/python3
import requests
from gpiozero import Button
import time
rain_sensor = Button(27)
bucket_size = 0.2794
count = 0
def bucket_tipped():
global count
count = count + 1
print(count * bucket_size)
def reset_rainfall():
global count
count = 0
#display and log results
def timed_loop():
reset_rainfall
timeout = time.monotonic() + 3600 # 1 hour from now
while True:
if time.monotonic() > timeout: # break if timeout time is reached
rain_sensor.when_pressed = bucket_tipped
time.sleep(1) # Short sleep so loop can be interupted
continue
print count
# close the log file and exit nicely
GPIO.cleanup()
It looks like you are continuously setting your rain to 0 in your while True: loop.
Edit:
Try something like this for your loop.
def timed_loop():
rain = 0
timeout = time.monotonic() + 3600 # 1 hour from now
while True:
if time.monotonic() > timeout: # break if timeout time is reached
# You place your code here that you want to run every hour.
# After that the loop restarts
rain = 1
time.sleep(1) # Short sleep so loop can be interupted
continue
Edit 3:
With the following code you can record button presses over a specified amount of time.
import time
def bucket_tip_counter():
recording_time_timeout = 3600 # Amount of seconds you want to have the timer run
recording_time = time.monotonic() + recording_time_timeout
button_timeout = 1 # This timeout is here so the button doesnt trigger the count more then once for each trigger
# You have to modify this to your needs. If the button stays activated for a few seconds you need to set the timer accordingly.
count = 0 # Sets the counter to 0 at the start
button = 0 # Here you need to replace the 0 with the GPIO pin that returns True if the button is pressed
while True: # starts the loop
if button: # if button gets pressed/bucket tipped
count += 1 # up count by one
time.sleep(button_timeout) # wait specified timeout to make sure button isnt pressed anymore
if time.monotonic() > recording_time: # If the recording_time is reached the loop triggers this if condition
print(count) # print count
# Here you can also place code that you want to run when the hour is over
# Note that the counter wont start back up until that code is finished.
count = 0 # set count back to 0
recording_time = time.monotonic() + recording_time_timeout # Set a new timer so the hour can start anew
continue # restart the loop
time.sleep(1) # small sleep to stop CPU hogging.

Threading infinity loops and sync problem

I am getting headache, trying to figure out how to deal with 2 threads in Python.
My Idea was to create one thread for blinking LEDs, that have infinite while loop, and when global variable changes to True,it starts to blink etc, but it is always in infinite loop.
other main thread, will be waiting for signal to blink, but also if the signal is while blinking, it will reset global blinking timer, so it has to be in separate thread.
Problem I am having, when I start LEDs thread from main thread, because LED thread has infinite loop, it stops main thread from running any further than flashThread.start()
if __name__ == "__main__":
print('starting main...')
flashThread = threading.Thread(name='SFlashing', daemon = True, target=Flash)
flashThread.start()
while(True):
print('running main...')
time.sleep(2)
it never gets to running main...
Flash() is just infinite while loop and depending on global variables it does stuff...
Here is an example of a main thread printing running main... + a parallel thread incrementing a variable count, based on your explanations. Your code should work, maybe could you give us more information about the Flash loop so we can help you ?
import threading
import time
def Flash():
count = 0
while True:
print("count", count)
count += 1
time.sleep(1)
print('starting main...')
flashThread = threading.Thread(name='SFlashing', daemon = True, target=Flash)
flashThread.start()
while(True):
print('running main...')
time.sleep(2)
Output:
starting main...
count 0
running main...
count 1
running main...
count 2
count 3
running main...
** EDIT **
Here there is no more time.sleep()in Flash, until the global variable totois changed in the main loop.
import threading
import time
global toto
toto = 0
def Flash():
global toto
count = 0
while True:
print("count", count)
count += 1
if toto == 2:
print("YEEHA")
time.sleep(2)
print('starting main...')
flashThread = threading.Thread(name='SFlashing', daemon = True, target=Flash)
flashThread.start()
while(True):
print('running main...')
time.sleep(1)
toto = 2

Pygame + python: 1 part of code has pygame.wait while rest of code runs

I am making a game in which u have to carry move objects from one place to another. I can move my character to the zone in which I need to put something. I want the player to wait in the zone for 5 secs before the object is placed there, however, if i do this you cannot move anymore if u decide u dont want to place the object in the zone as the whole script would be paused.
Is there a way to make one part of the script wait while the rest of it runs?
Every game needs one clock to keep the game loop in sync and to control timing. Pygame has a pygame.time.Clock object with a tick() method. Here's what a game loop could look like to get the behaviour you want (not complete code, just an example).
clock = pygame.time.Clock()
wait_time = 0
have_visited_zone = False
waiting_for_block_placement = False
# Game loop.
while True:
# Get the time (in milliseconds) since last loop (and lock framerate at 60 FPS).
dt = clock.tick(60)
# Move the player.
player.position += player.velocity * dt
# Player enters the zone for the first time.
if player.rect.colliderect(zone.rect) and not have_visited_zone:
have_visited_zone = True # Remember to set this to True!
waiting_for_block_placement = True # We're now waiting.
wait_time = 5000 # We'll wait 5000 milliseconds.
# Check if we're currently waiting for the block-placing action.
if waiting_for_block_placement:
wait_time -= dt # Decrease the time if we're waiting.
if wait_time <= 0: # If the time has gone to 0 (or past 0)
waiting_for_block_placement = False # stop waiting
place_block() # and place the block.
Example with threading:
from threading import Thread
def threaded_function(arg):
# check if it's been 5 seconds or user has left
thread = Thread(target = threaded_function, args = (10, ))
if user is in zone:
thread.start()
# continue normal code
Another potential solution is to check the time the user went into the zone and continuously check the current time to see if it's been 5 seconds
Time check example:
import time
entered = false
while true:
if user has entered zone:
entered_time = time.time()
entered = true
if entered and time.time() - entered_time >= 5: # i believe time.time() is in seconds not milliseconds
# it has been 5 seconds
if user has left:
entered=false
#other game code

How to interrupt input after 30 seconds and quit from program? - automatic logout - Python

I would like to make automatic logout after 30 seconds.
Program waits for user to input something and after 30 seconds I would like program to automatically shut down.
I have something like this:
import sys, time, os
def start_controller(user):
start = time.time()
PERIOD_OF_TIME = 30
os.system('clear')
print_menu() #printing menu
choice = get_choice() #get input from view model
while choice != "0":
os.system('clear')
if choice == "1":
start += PERIOD_OF_TIME
print_student_list(Student.student_list,AllAttendance.all_attendance_list)
if time.time() > start + PERIOD_OF_TIME:
os.system("clear")
print('logout')
Database.save_all_data_to_csv()
sys.exit()
Here's a simple example of using threads to get and process user input with a timeout.
We create a Timer thread to perform the timeout function, and wait for the user input in a daemon thread. If the user supplies an input string within the nominated delay period then the Timer is cancelled, otherwise the Timer will set the finished Event to break the while loop. If you need to do any final cleanup, you can do that after the while loop.
from threading import Thread, Timer, Event
def process_input(timer):
s = input('> ')
timer.cancel()
print(s.upper())
delay = 30
finished = Event()
while not finished.isSet():
timer = Timer(delay, finished.set)
worker = Thread(target=process_input, args=(timer,))
worker.setDaemon(True)
worker.start()
timer.start()
timer.join()

sleep without interrupting program

I am creating a program that counts down after a time, and asks for input of seconds to add to the countdown. (Not really, just an example).
Kind of like this:
mytime = 10
while True:
print(time)
mytime -= 1
time.sleep(1)
mytime += int(input('add > '))
There is 2 problems.
I want the time to still tick down after a second, but don't want to have to wait the second before inputting. Similar to this. I think I need to use threading.
I don't want to wait for input either! I just want it to tick down without waiting for input, and when I want I can input things.
Thanks for your help.
There is an easier way than making your own thread from 0. Timer thread prepared for you:
import threading
timer = None
def wuf ():
global timer
print "Wuf-wuf!"
timer = threading.Timer(5, wuf)
timer.start()
timer = threading.Timer(5, wuf)
timer.start()
input() # Don't exit the program
This code will wait 5 seconds and then start printing "Wuf-wuf!" every 5 seconds.
If you want to stop it from main thread do:
timer.cancel()
But if you are writing a GUI application using event driven GUI system like wxPython or PyQT, then you should use theirs event managed timers. Especially if you are changing some GUI status from the timer callback.
Edit:
Oh, all right, here is your full answer:
import threading
seconds = 1 # Initial time must be the time+1 (now 0+1)
timer = None
def tick ():
global seconds, timer
seconds -= 1
if seconds==0:
print("%i seconds left" % seconds)
print("Timer expired!")
return
# printing here will mess up your stdout in conjunction with input()
print("%i second(s) left" % seconds)
timer = threading.Timer(1, tick)
timer.start()
seconds += int(input("Initial countdown interval: "))
tick()
while 1:
seconds += int(input("Add: "))
if not timer.is_alive():
print("Restarting the timer!")
seconds += 1
tick()
Or easy version with thread (but a little clumsyer then using threading.Thread):
from thread import start_new_thread as thread
from time import sleep
seconds = 1 # Initial time+1
alive = 0
def _tick ():
global seconds, alive
try:
alive = 1
while 1:
seconds -= 1
if seconds==0:
print("%i seconds left" % seconds)
print("Timer expired!")
alive = 0
return
# printing here will mess up your stdout in conjunction with input()
print("%i second(s) left" % seconds)
sleep(1)
except: alive = 0
def tick ():
thread(_tick,())
# Then same as above:
seconds += int(input("Initial countdown interval: "))
tick()
while 1:
seconds += int(input("Add: "))
if not alive:
print("Restarting the timer!")
seconds += 1
tick()
You must realize that using the stdout within a thread will insert the printed text after the prompt message outputed by input().
This will be confusing. If you want to avoid this then you will have to write another thread that will get messages from a queue and output them.
If a last message was prompt message, then you will have to remove it from screen, write the new message, then return the prompt message, and position the cursor accordingly.
You could do it by implementing the file-like interface within the subclass of threading.Thread, then substituting sys.stdout with it. Perhaps overriding input() as well to indicate when a prompt message is out and stdin being read.
You'll need to use threading to do so. All you have to do is create a subclass of threading.Thread override the run() method and add some external control methods over the thread.
Here is a simple example you can try and tweak according to your own taste.
import threading
import time
class SleepingThread(threading.Thread):
def __init__(self, sleep_for):
super(SleepingThread, self).__init__()
self.sleep_for = sleep_for
def run(self):
while self.sleep_for != 0:
time.sleep(1)
self.sleep_for -= 1
print("Done sleeping")
def add_seconds(self, seconds):
self.sleep_for += seconds
def get_sleep_for(self):
return self.sleep_for
sleeping_thread = SleepingThread(10)
sleeping_thread.start()
while True:
print(sleeping_thread.get_sleep_for())
sleeping_thread.add_seconds(int(input('add > ')))
Don't forget to join() if you want to go serious about it.

Categories

Resources