Re: [python-win32] Restart/re-run a thread
The python docs are pretty clear that there is no way to external stop a thread and this was a design decision. Typically, I have used a threading.Event to control the actions of the worker threads from a loop in the main program. Setup each worker thread as a loop using the event.wait() method to block the loop. When you are ready for all of the threads to proceed, use the controller thread and event.set(). All of the worker threads will exit the blocking state of their loop and proceed with execution. Once finished, they return to the event.wait() mode. To stop the threads, I typically use another thread.Event object called keepgoing and test for that at the top of the worker threads processing loop. When the threads have finished processing and you want them to stop, you can set the keepgoing event to false. The example below is from memory, so be careful; keepgoing = threading.Event() keepgoing.set() # evaluates to True startprocess = threading.Event() startprocess.clear() # evaluates to False class worker(threading.Thread): def __init__(self, keepgoing, startprocess): while keepgoing: if startprocess: ... do someprocessing here else: startprocess.wait()#blocks the thread waiting for the event to be set. Note that if you need to pass objects into the worker thread, I would suggest placing in a collections.deque. One the startprocess is set, you can use deque.pop() to take the object out of the deque in a thread safe way. Hope this helps. BTW, I am not sure if this is for education purposes or for production, but debugging threads is REALLY HARD, so make sure this is something you really need to do. ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Restart/re-run a thread
Jacob, What you are looking at is called a thread pool. The simple case you have now is that you start a thread whenever there is work to do (playing a sound). The thread does this work, then exits. A thread pool means you have a set number of threads idling and receiving work via a queue. When work appears, they perform it and then go back to idle. There are thread pool implementations for Python that you could simply plug into your application. from multiprocessing.pool import ThreadPool http://code.activestate.com/recipes/203871-a-generic-programming-thread-pool/ In either case, if you are looking to kill off a thread midway through the work (cut off the sound before it is done playing). Then you will need to use a flag to inform the thread that you wish for it to stop playing sound. This means you need a polling loop that will play a short sample of the track and then check the flag before playing the next sample. This way the thread can exit part of the way through the sound. A thread pool will not save memory. It saves the setup/teardown of threads. This is a relatively expensive process, and if an application starts hundreds of thousands of threads during it's lifetime, this adds up. Think about it, either way, you will need a number of concurrent threads that equals the number of sounds you wish to play concurrently. This means a thread pool will have X threads active (though idle) at all times. The simple case will have X threads active (and working) only while the sounds are being played. The only real advantage of the thread pool is that it avoids setup/teardown, so it could possibly save some latency when playing a new sound. This is because a new thread does not need to be initialized, it just has to wake up and start playing the sound. You have to decide if this latency is a problem and if so, go the thread pool route. Of course, Python threads are not native threads, so I think any advantage here probably washes out. My suggestion is to stick with the simple case. A simple sound player class can do the whole task for you, and your code will be much easier to follow and debug. Throwing a thread pool into the mix will complicate things. Simple case: class PlaySound(threading.Thread): def __init__(self, sound='foobar.wav'): self.sound = sound self.running = True self.sample = 0 threading.Thread.__init__(self): self.start() def playsample(self): soundlib.play(self.sound, startms=self.sample*100, lengthms=100) self.sample += 100 def run(self): while self.running: self.playsample() def stop(self): self.running = False s = PlaySound('explosion.wav') if user_exited: s.stop() The main key here is that instead of playing the whole sound file in one shot, you play only a small portion of it between polls. This way the thread can stop mid-sound. You need to use a sound library that will support breaking a sound into multiple parts in order to achieve this. Another option here is to ditch threads altogether and find a sound library that does async playback. Let it handle this mess for you. http://docs.python.org/library/winsound.html ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Restart/re-run a thread
Thanks. What have also found that seems nice/usable enough is to sort of implement a class that inherits from threading.Thread, and then it runs the class's functionality in the threaded background, and you can define other functions and variables to check state if you want to - something like the following - off the top of my head: #---start of code--- import threading, time class myClass(threading.Thread): counter = -1 def __init__(self): self.counter = 0 threading.Thread.__init__(self) def getCount(self): return self.counter def run(self): while self.counter 60: self.counter += 1 time.sleep(1) #---end of code--- The partial point is this one will be initiated, but when you then tell your instance of the class/object to start(), it sort of automatically tells itself to run(), and you can call the getCount() function to get the value of it's internal counter variable, etc. - simple example, but seems to work well enough, if you get my/the drift, and, what have pretty much found all over the 'net is that you get told not to try destroy anything manually/yourself, but anyway. Stay well Jacob Kruger Blind Biker Skype: BlindZA '...fate had broken his body, but not his spirit...' - Original Message - From: geoff To: Jacob Kruger Cc: python-win32@python.org Sent: Thursday, October 27, 2011 3:47 PM Subject: Re: [python-win32] Restart/re-run a thread The python docs are pretty clear that there is no way to external stop a thread and this was a design decision. Typically, I have used a threading.Event to control the actions of the worker threads from a loop in the main program. Setup each worker thread as a loop using the event.wait() method to block the loop. When you are ready for all of the threads to proceed, use the controller thread and event.set(). All of the worker threads will exit the blocking state of their loop and proceed with execution. Once finished, they return to the event.wait() mode. To stop the threads, I typically use another thread.Event object called keepgoing and test for that at the top of the worker threads processing loop. When the threads have finished processing and you want them to stop, you can set the keepgoing event to false. The example below is from memory, so be careful; keepgoing = threading.Event() keepgoing.set() # evaluates to True startprocess = threading.Event() startprocess.clear() # evaluates to False class worker(threading.Thread): def __init__(self, keepgoing, startprocess): while keepgoing: if startprocess: ... do someprocessing here else: startprocess.wait()#blocks the thread waiting for the event to be set. Note that if you need to pass objects into the worker thread, I would suggest placing in a collections.deque. One the startprocess is set, you can use deque.pop() to take the object out of the deque in a thread safe way. Hope this helps. BTW, I am not sure if this is for education purposes or for production, but debugging threads is REALLY HARD, so make sure this is something you really need to do. ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Restart/re-run a thread
Thanks. winsound.PlaySound(file.wav, winsound.SND_ASYNC) Does handle it asynchronously, but, yes, thanks for complete example. Am in any case still trying to find/get hold of a sound library of some sort that will do a bit more, like I want it to, and one called pyaudiere works fine on my windows7 32bit machine, but refuses to work on my windows7 64bit machine, same as another wrapper module called sound_lib - and main thing I would like, apart from just playing/stopping/pausing sounds is to be able to handle a little bit of 3D, like panning playback etc., but not end of the world thus far. Stay well Jacob Kruger Blind Biker Skype: BlindZA '...fate had broken his body, but not his spirit...' - Original Message - From: Ben Timby bti...@gmail.com To: python-win32@python.org Sent: Thursday, October 27, 2011 4:31 PM Subject: Re: [python-win32] Restart/re-run a thread Jacob, What you are looking at is called a thread pool. The simple case you have now is that you start a thread whenever there is work to do (playing a sound). The thread does this work, then exits. A thread pool means you have a set number of threads idling and receiving work via a queue. When work appears, they perform it and then go back to idle. There are thread pool implementations for Python that you could simply plug into your application. from multiprocessing.pool import ThreadPool http://code.activestate.com/recipes/203871-a-generic-programming-thread-pool/ In either case, if you are looking to kill off a thread midway through the work (cut off the sound before it is done playing). Then you will need to use a flag to inform the thread that you wish for it to stop playing sound. This means you need a polling loop that will play a short sample of the track and then check the flag before playing the next sample. This way the thread can exit part of the way through the sound. A thread pool will not save memory. It saves the setup/teardown of threads. This is a relatively expensive process, and if an application starts hundreds of thousands of threads during it's lifetime, this adds up. Think about it, either way, you will need a number of concurrent threads that equals the number of sounds you wish to play concurrently. This means a thread pool will have X threads active (though idle) at all times. The simple case will have X threads active (and working) only while the sounds are being played. The only real advantage of the thread pool is that it avoids setup/teardown, so it could possibly save some latency when playing a new sound. This is because a new thread does not need to be initialized, it just has to wake up and start playing the sound. You have to decide if this latency is a problem and if so, go the thread pool route. Of course, Python threads are not native threads, so I think any advantage here probably washes out. My suggestion is to stick with the simple case. A simple sound player class can do the whole task for you, and your code will be much easier to follow and debug. Throwing a thread pool into the mix will complicate things. Simple case: class PlaySound(threading.Thread): def __init__(self, sound='foobar.wav'): self.sound = sound self.running = True self.sample = 0 threading.Thread.__init__(self): self.start() def playsample(self): soundlib.play(self.sound, startms=self.sample*100, lengthms=100) self.sample += 100 def run(self): while self.running: self.playsample() def stop(self): self.running = False s = PlaySound('explosion.wav') if user_exited: s.stop() The main key here is that instead of playing the whole sound file in one shot, you play only a small portion of it between polls. This way the thread can stop mid-sound. You need to use a sound library that will support breaking a sound into multiple parts in order to achieve this. Another option here is to ditch threads altogether and find a sound library that does async playback. Let it handle this mess for you. http://docs.python.org/library/winsound.html ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32 ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32
Re: [python-win32] Restart/re-run a thread
Will check it out, but will also just say that a few of the game libraries I have looked at already are of no interest to me, since they produce inaccessible output/interfaces, but, will look into them a bit more for sound output...:) Have also gotten hold of another, sort of TTS module/wrapper that makes use of actual screen reader voices in meantime, and which works with python 2.7, which is what am using at the moment, but anyway: http://hg.qwitter-client.net/accessible_output/ Stay well Jacob Kruger Blind Biker Skype: BlindZA '...fate had broken his body, but not his spirit...' - Original Message - From: Ben Timby bti...@gmail.com To: Jacob Kruger jac...@mailzone.co.za Sent: Thursday, October 27, 2011 5:34 PM Subject: Re: [python-win32] Restart/re-run a thread Jacob, May be getting a bit off topic here :-). However, for 3D sound, look for python game libraries. For cross-platform 3D sound, it looks like you might want FMOD. There is pySonic, a python wrapper for FMOD. http://pysonic.sourceforge.net/ FMOD is non-free. However, it is gratis for non-commercial use. I am sure there are other options as well, but I suggest looking for libraries geared toward games since they will have the features you apparently need. Good luck! ___ python-win32 mailing list python-win32@python.org http://mail.python.org/mailman/listinfo/python-win32