python: adding a reset function to a threaded application - python

My python code runs a function that takes a long time:
Navigation()
During this execution I'd like to have a reset button. For reset button to work, I used threading and I managed to get my code into threaded callback function with the button press. How do I terminate the Navigation() that is currently running and call another fresh Navigation() function? thanks.
Thanks in advance.

If your navigation function has a loop that it executes, you could have a check to see if an "interrupt" variable is set to True. If so, you could have the Navigation function terminate during that check:
def navigation(self):
# reset self.interrupt as appropriate
while not self.interrupt:
pass # Do something here
# You will want some other exit condition as well, of course.
def button_pressed_response(self):
self.interrupt = True
self.navigation()
If you have access to a multithreaded library as you indicated, you could use a more elegant callback function and simplify the reset logic as well.

This answer pretty much sums up issues and pitfalls of terminating threads:
https://stackoverflow.com/a/325528

Related

Python function call not runing correcly from thread

I'm having some trouble getting this to work, i'm trying to append GUI texts to a window that allready exists, i'm using the python interpreter for autodesk maya, i attach here part of the host script where i check for multiple connections and try to add the text for each connection.
The problem comes when calling the interpHostData() function from inside the while loop inside the thread, it dosnt add anything to the window;
But whenever i call the function by itself outside of a thread it works correctly.
If anyone has a clue on how can i fix this i would apreciate it, thanks in advance.
def hostUpdate():
global socketHost
global clientL
clientL=[]
cmds.text('mt1',e=1,l='Update Process Started...')
while 1:
connectionMain,addressMain=socketHost.accept()
cmds.text('mt1',e=1,l='Connected with: %s'%str(addressMain))
#----------Different Thread for each connection
tid=thr.start_new_thread(hostRecieve,(connectionMain,addressMain))
clientL.append([connectionMain,addressMain,tid])
cmds.text('mt1',e=1,l='Thread started with: %s'%str(addressMain))
def hostRecieve(connI,addrI):
global clientL
cmds.text('mt1',e=1,l='Recieve Process Started...')
while 1: #------------------------------------Loop to keep listening for connections
try:
cmData=connI.recv(4096)
interpHostData(cmData) #--------------IF I CALL FROM HERE DOSN'T WORK
except:
for cl in clientL:
if connI==cl[0]:
clientL.remove(cl)
cmds.text('mt1',e=1,l='Disconnected from %s'%str(addrI))
break
def interpHostData(cmDataC):
global cliLayout
tplD=cmDataC.split(',')
if tplD[0]=='0':
cID=tplD[2]
cmds.setParent(cliLayout)
cmds.text(cID+'_1',l=tplD[1])
cmds.text(cID+'_2',l=tplD[3])
cmds.text(cID+'_3',l=tplD[4])
cmds.text(cID+'_4',l='_')
cmds.text(cID+'_5',l='_')
cmds.text(cID+'_6',l='_')
cmds.text(cID+'_7',l='_')
cmds.text(cID+'_8',l='_')
cmds.columnLayout(cID+'_9')
cmds.progressBar(cID+'_10',h=10)
cmds.progressBar(cID+'_11',h=10)
cmds.setParent(cliLayout)
cmds.text(cID+'_12',l='_')
cmds.text(cID+'_13',l='Online')
You can only run Maya ui commands from the main thread. You can use maya.util.ExcecuteDeferred() to get around this to some degree but it takes extra work and won't be as responsive as a true multi-threaded app. Longer explanation in this question

How can a Python function be called on script exit reliably?

How do you register a function with all the correct handlers etc to be called when the Python script is exitted (successfully or not)?
I have tried:
#atexit.register
def finalise():
'''
Function handles program close
'''
print("Tidying up...")
...
print("Closing")
...but this does not get called when the user closes the command prompt window for example (because #atexit.register decorated functions do not get called when the exitcode is non zero)
I am looking for a way of guaranteeing finalise() is called on program exit, regardless of errors.
For context, my Python program is a continually looping service program that aims to run all the time.
Thanks in advance
I don't think it can be done in pure Python. From documentation:
Note: the functions registered via this module are not called when the
program is killed by a signal not handled by Python, when a Python
fatal internal error is detected, or when os._exit() is called.
I think you may find this useful: How to capture a command prompt window close event in python
Have you tried to just catch all kinds of exceptions in your main function or code block?
For context, my Python program is a continually looping service program that aims to run all the time.
This is very hard to get right (see How do you create a daemon in Python?). You should use a library like http://pypi.python.org/pypi/python-daemon/ instead.
This one should work
works both on Ctrl-C and when the assertion fails. Maybe you can use a similar construct and pack it as a decorator, or whatever.
def main():
print raw_input('> ')
# do all your stuff here
if __name__ == '__main__':
try:
main()
finally:
print 'Bye!'
atexit.register(func)
func = lambda x: x
Use http://docs.python.org/2/library/atexit.html

pygtk's strange problem about set button's sensitive property

on one of my methods, I have the following code:
def fun():
self.button1.set_sensitive(False)
self.get_time()
However, self.button1 only becomes insensitive after get_time() return !!,use the time.sleep(n) replace the get_time() could get same result
Any clue why?
I think programmic changes to widgets applies in the next lap of event loop (gtk.main()), that is probably after finishing fun function. Does that make a problem for you? How much time self.get_time()
takes? If that takes a sensible time, you can update widgets before that:
def fun():
self.button1.set_sensitive(False)
while gtk.events_pending():
gtk.main_iteration_do(False)
self.get_time()
Uhh are you sure you want to do that?
All GUI programming events are done by message passing and so you really shouldn't block the main thread for long enough you'd ever need some workaround like this. And if you do that, you'll soon have other problems like the window manager killing your window because it's not responding to ping or reentrance problems when you do the iteration. If you have some complicated task like burning a CD or whatever that takes that long, put the actual burning into its own executable and call it by glib.spawn_async (or similar). Use gobject.child_watch_add to ask to be notified about termination.

When while loop placed in wxPython events

I'm trying to write a GUI program grabbing specific contents from a webpage. The idea is when I hit the start button, the program should start extracting information from that page. And I want to add some code to check if connected to the Internet. If not, continue trying until connected.
So I just added the following code in the event, but found it didn't work. Also the whole program has to be closed in a forced way. Here's my code:
import urllib2
import time
InternetNotOn = True
while InternetNotOn:
try:
urllib2.urlopen("http://google.com")
InternetNotOn = False
print "Everyting is fine!"
except urllib2.URLError, e:
print "Error!"
time.sleep(10)
What could the problem be?
When you have an event based program, the overall flow of the program is this:
while the-program-is-running:
wait-for-an-event
service-the-event
exit
Now, lets see what happens when service-the-event calls something with a (potentially) infinite loop:
while the-program-is-running:
wait-for-an-event
while the-internet-is-on:
do-something
exit
Do you see the problem? In the worse case your program may never call wait-for-an-event again because your loop is running.
Remember: the event loop is already an infinite loop, you don't need to add another infinite loop inside of it. Instead, take advantage of the existing loop. You can use wx.CallAfter or wx.CallLater to call a method which will cause your function to be called at the next iteration of the event loop.
Then, within your function you call wx.CallAfter or wx.CallLater again to cause it to again be called on the next iteration of the event loop.
Instead of time.sleep(10) you can call wxApp::Yield and time.sleep(1) ten times.
Beware of reentrancy problems (e.g. pressing the start button again.). The start button could be dimmed while in the event handler.
But Bryan Oakley's solution is probably the better way.

wxPython: Using EVT_IDLE

I defined an handler for EVT_IDLE that does a certain background task for me. (That task is to take completed work from a few processes and integrate it into some object, making a visible change in the GUI.)
The problem is that when the user is not moving the mouse or doing anything, EVT_IDLE doesn't get called more than once. I would like this handler to be working all the time. So I tried calling event.RequestMore() at the end of the handler. Works, but now it takes a whole lot of CPU. (I'm guessing it's just looping excessively on that task.)
I'm willing to limit the number of times the task will be carried out per second; How do I do that?
Or do you have another solution in mind?
Something like this (executes at most every second):
...
def On_Idle(self, event):
if not self.queued_batch:
wx.CallLater(1000, self.Do_Batch)
self.queued_batch = True
def Do_Batch(self):
# <- insert your stuff here
self.queued_batch = False
...
Oh, and don't forget to set self.queued_batch to False in the constructor and maybe call event.RequestMore() in some way in On_Idle.
This sounds like a use case for wxTimerEvent instead of wxIdleEvent. When there is processing to do call wxTimerEvent.Start(). When there isn't any to do, call wxTimerEvent.Stop() and call your methods to do processing from EVT_TIMER.
(note: i use from wxWidghets for C++ and am not familiar with wxPython but I assume they have a similar API)

Categories