I'm currently developing a GUI for a 3D printer and I'm having a problem of how to stop a threading function. I want to be able to click a button that has another function within my GUI that will stop the threading function from sending strings of G-code across the serial port. Currently the function has threading incorporated to allow other functions to be triggered during printing. I would greatly appreciate some advice on how I would incorporate this stop feature.
Below is the function that opens a G-code file and sends each line across the serial port.
def printFile():
def callback():
f = open(entryBox2.get(), 'r');
for line in f:
l = line.strip('\r')
ser.write("<" + l + ">")
while True:
response = ser.read()
if (response == 'a'):
break
t = threading.Thread(target=callback)
t.start()
Threads cannot be stopped, they have to stop themselves. So you need to send a signal to the thread that it's time to stop. This is usually done with an Event.
stop_event = threading.Event()
def callback():
f = open(entryBox2.get(), 'r');
for line in f:
l = line.strip('\r')
ser.write("<" + l + ">")
while True:
response = ser.read()
if (response == 'a'):
break
if stop_event.is_set():
break
t = threading.Thread(target=callback)
t.start()
Now if you set the event elsewhere in your code:
stop_event.set()
The thread will notice that, break the loop and die.
Use a global variable as a condition for the thread to stop.
send_gcode = True
def printFile():
def print_thread():
f = open(entryBox2.get(), 'r');
for line in f:
if not send_gcode:
break
l = line.strip('\r')
ser.write("<" + l + ">")
while True:
response = ser.read()
if (response == 'a'):
break
t = threading.Thread(target=print_thread)
send_gcode = True
t.start()
The thread will run until send_gcode is set to False (by e.g. a callback for a button:
def stop_callback(event):
global send_gcode
send_gcode = False
Related
I have the following loop which is calling the getHLS function in a separate thread for each of the text lines. The problem is that the getHLS function might be really slow at some times, and I am looking for a way to "timeout" a thread if the function does not return anything for 10 seconds.
links = open("links.txt")
lines = links.readlines()
linenumber = 0
for line in lines:
linenumber += 1
thread = threading.Thread(target = getHLS, args = (line, linenumber))
thread.setDaemon(False)
thread.start()
if threading.active_count() == 50:
thread.join(10)
I am coding a discord bot with python, I am running into difficulties with the next feature. When the message: ('user' joined) is read the bot should start looping the function every x seconds until the message: ('user' left) is read.
I have been testing different code in scratch files. It succesfully starts looping at 'user' joined. But when the ('user' left) message should come through it won't take the new argument and continues the loop forever.
These two versions look most promising:
import re
import time
def message(servermessage):
a = re.sub("[^\S]", " ", servermessage).split()
if a[1] == 'joined':
online = False
elif a[1] == 'left':
online = True
while True:
mcusername = a[0]
print(mcusername, 0)
if online:
break
time.sleep(2)
message('user joined')
time.sleep(10)
message('user left')
and
import re
import sched, time
s = sched.scheduler(time.time, time.sleep)
def message(servermessage):
a = re.sub("[^\S]", " ", servermessage).split()
def rewardplayer():
s.enter(1, 1, rewardplayer)
mcusername = a[0]
print(mcusername, 0)
if a[1] == 'joined':
s.enter(1, 1, rewardplayer)
s.run()
elif a[1] == 'left':
s.cancel()
message('user joined')
time.sleep(10)
print('done')
message('user left')
Another requirement that I have is that it should be able to run the same loop for a different user when a ('newuser' joined) message is given before the ('previoususer' left) message from a previous user.
I apologise for the vague explanation. But I hope you can help. Thanks in advance!
About your first code:
there you have while which should be broken when online is True. But its never changing inside that loop. So its similar to deadlock.
About your second code:
there you are using "scheduler". Usually it means you want to run some events periodically. But your aim is to react when event was happened. In any time. Not schedulled.
So here I can recommend you to use async python way.
(please, read about asyncio)
import re
import asyncio
async def process_msgs(queue):
while True:
msg = await queue.get()
online, usr_name = parse_msg(msg)
print(usr_name, 0)
queue.task_done()
def parse_msg(msg):
result = re.sub("[^\S]", " ", msg).split()
action = result[1]
usr_name = result[0]
if action == 'joined':
online = False
elif action == 'left':
online = True
return online, usr_name
async def main():
queue = asyncio.Queue()
queue.put_nowait('usr joined')
task = asyncio.create_task(process_msgs(queue))
queue.put_nowait('usr left')
await queue.join()
task.cancel()
asyncio.run(main())
You can use it like that.
There we have a queue, where we put our events. You can do that through infinite way too (listen socket or smthg - here you will get msg about different users).
And we have task (worker), which work while our "main" function is alive.
complete python newbie...
I'm working with the Arduino pyfirmata package and Im trying to do something quite simple.
Depending on a user input to python, I want an LED to flash or not.
My problem is that the python program only asks for the user input once but I would like it to always ask for the input so the user can change function at any time.
I have tried using the threading package but no success... Perhaps there is a simpler way, but I am totally new to coding so I do not know of any other. Open to suggestions!!
Here is my code,
import pyfirmata
import threading
import time
board = pyfirmata.Arduino('/dev/cu.usbmodem14101')
def flash():
for i in range(1000):
board.digital[13].write(1)
time.sleep(1)
board.digital[13].write(0)
time.sleep(1)
def stop():
board.digital[13].write(0)
while True:
runMode = input("Run or Stop? ")
if runMode == "Run":
x = threading.Thread(target=flash(), args=(1,))
x.start()
# x.join()
elif runMode == "Stop":
x = threading.Thread(target=stop(), args=(1,))
x.start()
#x.join()
You can do it in an object-oriented way by creating your own Thread subclass something like the Flasher class below.
One of the advantages to this approach is that it would be relatively easy to extend the Flasher class and make it control LEDs connected to different outputs, or to allow the delay between flashes to be specified at creation time. Doing the former would allow multiple instances to be running at the same time.
import pyfirmata
import threading
import time
OFF, ON = False, True
class Flasher(threading.Thread):
DELAY = 1
def __init__(self):
super().__init__()
self.daemon = True
self.board = pyfirmata.Arduino('/dev/cu.usbmodem14101')
self.flashing = False
self.LED_state = OFF
def turn_LED_on(self):
self.board.digital[13].write(1)
self.LED_state = ON
def turn_LED_off(self):
self.board.digital[13].write(0)
self.LED_state = OFF
def run(self):
while True:
if self.flashing:
if self.LED_state == ON:
self.turn_LED_off()
else:
self.turn_LED_on()
time.sleep(self.DELAY)
def start_flashing(self):
if self.LED_state == OFF:
self.turn_LED_on()
self.flashing = True
def stop_flashing(self):
if self.LED_state == ON:
self.turn_LED_off()
self.flashing = False
flasher = Flasher()
flasher.start()
while True:
runMode = input("Run or Stop? ").strip().lower()
if runMode == "run":
flasher.start_flashing()
elif runMode == "stop":
flasher.stop_flashing()
else:
print('Unknown response ignored')
If your looking to just kill the thread you could use mulitiprocessing
which a multiprocessing.Process can p.terminate()
p = Process(target=flash, args=(,))
while True:
runMode = input("Run or Stop? ")
if runMode == "Run":
p.start()
elif runMode == "Stop":
p.terminate()
However this is not recommended to just kill threads as it can cause errors if the process is handling critical resources or dependant on other threads see here for a better explanation Is there any way to kill a Thread?
A better option as described here is to use flags to handle your flashing, they allow a simple communication between threads
from threading import Event
e = event()
def check_for_stop(e):
while not e.isSet():
flash()
print("Flashing Ended")
while True:
runMode = input("Run or Stop? ")
if runMode == "Run":
x = threading.Thread(target=check_for_stop, args=(e,))
x.start()
# x.join()
elif runMode == "Stop":
e.set() #set flag true
e.clear() #reset flag
here is the documentation for more info on event objects https://docs.python.org/2.0/lib/event-objects.html
I havent tested this code is just an example so apologies if it doesnt work straight away
Edit: Just looking at your function again you would want to check for the flag during the flashing thats my mistake aplogies so your flash function would look like
def flash():
while e.isSet():
board.digital[13].write(1)
time.sleep(1)
board.digital[13].write(0)
time.sleep(1)
and you would pass this into the thread as you have before
x = threading.Thread(target=flash(), args=(1,))
x.start()
You got an error in the code.
You should create the thread via:
x = threading.Thread(target=flash)
Note: You gave the entered 'flash()' therefore executing the method in the main thread. And also your method doesn't have any arguments therefore you can remove the args values
Hi why is my KeyboardInterrupt: is not stoping my program when i hit control c or control x? this is my current code.
I am using python Threading that runs 2 function coinPulser and coinPulserDone.
import threading
import time
lock = threading.Lock()
counter = 0
input = 3
def coinPulser ():
global counter
global input
lock.acquire()
try:
while counter < input:
counter+=1
time.sleep(.1)
if counter in [1,3,5]:
print(counter)
return counter
finally:
lock.release()
def coinPulserDone ():
while True:
print(coinPulser())
try:
coinpulser = threading.Thread(target = coinPulser)
coinpulser.start()
coinpulserdone = threading.Thread(target = coinPulserDone)
coinpulserdone.start()
except KeyboardInterrupt:
coinpulser.stop()
coinpulserdone.stop()
print('Thread Stops')
I suspect the problem is that your code exits your try/except block before you press Cntr-C. You need to add some form of a loop that will hold it in that block. A simple loop such as
while True:
time.sleep(1)
before your except line should do the trick.
I am currently generating a python-script with the fabric framwork that is supposed to collect a backup from a remote server and store it locally on the client running fabric.
Now, since the backup file is >400MB, it takes quite some time to transfer it. And here is where my question bumps in:
Is there any kind of progressbars for the fabric get()-function? Or rather, is it possible to add a progressbar somehow?
Here's a piece of my code:
def collect_backup():
env.warn_only=True
run('uptime')
print "Copying scrips to be run..."
filename, remotepath = _getlatest()
print "Copy complete."
print "Collecting backup..."
localpath = _collect(filename, remotepath)
def _collect(filename, remotepath):
a=remotepath + filename
localpath="/home/bcns/backups/"
####Here's the get() I was talking about
get(a, localpath)
return(localpath)
The "filename" and "remotepath" variables are set in another function.
There is a lot of great info at the following site:
http://thelivingpearl.com/2012/12/31/creating-progress-bars-with-python/
Here is their solution for a console prog bar with threading:
import sys
import time
import threading
class progress_bar_loading(threading.Thread):
def run(self):
global stop
global kill
print 'Loading.... ',
sys.stdout.flush()
i = 0
while stop != True:
if (i%4) == 0:
sys.stdout.write('\b/')
elif (i%4) == 1:
sys.stdout.write('\b-')
elif (i%4) == 2:
sys.stdout.write('\b\\')
elif (i%4) == 3:
sys.stdout.write('\b|')
sys.stdout.flush()
time.sleep(0.2)
i+=1
if kill == True:
print '\b\b\b\b ABORT!',
else:
print '\b\b done!',
kill = False
stop = False
p = progress_bar_loading()
p.start()
try:
#anything you want to run.
time.sleep(1)
stop = True
except KeyboardInterrupt or EOFError:
kill = True
stop = True
Hope that helps or at least gets you started.