Stopping a Thread with Time Slicing

S

Steve

Hi All,

I've been trying to come up with a good way to run a certain process
at a timed interval (say every 5 mins) using the SLEEP command and a
semaphore flag. The basic thread loop was always sitting in the sleep
command and not able to be interrupted. When the time came to set the
semaphore flag to false (stopping the thread), my program would have
to wait up to the entire sleep time to break out of the loop.

I have finally found a very workable solution to break out of the
sleep loop by using a time slicing loop to divide the overall sleep
time into small pieces (slices) giving the loop more opportunities to
be interrupted.


Here is my code :

-------------------------------------------------------------

import time
import datetime
import threading


def log(message):

now = datetime.datetime.now().strftime("%H:%M:%S")
print "%s : %s" % (now, message)



class StoppableThread(threading.Thread):

def __init__(self, sleep_time, time_slice):

self.sleep_time = sleep_time
self.running = True
self.time_slice = time_slice

threading.Thread.__init__(self)


def run(self):

while self.running:

log('Thread Running...')
#process_some_data() ## <<-- Call some def here to perform
some timed task
log('## Do Some Work Here ##\n')

# Sleep Loop :
# Put sleeps in time_slice loop, with sleep = sleep_time /
time_slice
# This gives the sleep loop more opportunities to be interrupted
# when the running flag is set to False

for current_loop in range(0, self.time_slice) :

time.sleep(self.sleep_time / self.time_slice)

if not self.running: # check the flag
break # break out of the sleep loop


log('** Thread Has STOPPED!')


def stop(self): # stop the thread from running
self.running = False


#####################################################################
# T E S T
#####################################################################

SMALL_SLEEP = 35
CHECK_SLEEP = 300 # sleep interval in seconds to run a timed
process
TIME_SLICE = 100 # number of slices to divide CHECK_TIME
(higher number = faster kill response)


log('Create Thread')
thread_obj = StoppableThread(CHECK_SLEEP, TIME_SLICE)

log('Thread Start\n')
thread_obj.start()

for current_loop in range(0,10):
time.sleep(SMALL_SLEEP)
log('current loop = %d \n' % current_loop)

log('Thread Stop')
thread_obj.stop()

log('Done!')


--------------------------------------------

Test Results :
python Simple_Thread.py

15:37:23 : Create Thread
15:37:23 : Thread Start

15:37:23 : Thread Running...
15:37:23 : ## Do Some Work Here ##

15:37:58 : current loop = 0

15:38:33 : current loop = 1

15:39:08 : current loop = 2

15:39:43 : current loop = 3

15:40:18 : current loop = 4

15:40:53 : current loop = 5

15:41:28 : current loop = 6

15:42:03 : current loop = 7

15:42:23 : Thread Running...
15:42:23 : ## Do Some Work Here ##

15:42:38 : current loop = 8

15:43:13 : current loop = 9

15:43:13 : Thread Stop
15:43:13 : Done!
15:43:14 : ** Thread Has STOPPED!
 
T

Todd Whiteman

Steve said:
Hi All,

I've been trying to come up with a good way to run a certain process
at a timed interval (say every 5 mins) using the SLEEP command and a
semaphore flag. The basic thread loop was always sitting in the sleep
command and not able to be interrupted. When the time came to set the
semaphore flag to false (stopping the thread), my program would have
to wait up to the entire sleep time to break out of the loop.

I have finally found a very workable solution to break out of the
sleep loop by using a time slicing loop to divide the overall sleep
time into small pieces (slices) giving the loop more opportunities to
be interrupted.

A better approach for this is to use a Python Event or Condition object:
http://docs.python.org/library/threading.html#id5

Example code:


import threading
my_stop_event = threading.Event()

# Sleep Loop :
#for current_loop in range(0, self.time_slice) :
# time.sleep(self.sleep_time / self.time_slice)

event.wait(self.sleep_time)
if not self.running: # check the flag
break # break out of the sleep loop

# From another thread, you can notify the above sleeping thread using:
my_stop_event.set()


Cheers,
Todd
 
S

Steve

Hi Todd,

Thanks for your suggestions on using the Event condition methods on
this thread.

Here is my updated code :


import time
import datetime
import threading


def log(message):

now = datetime.datetime.now().strftime("%H:%M:%S")
print "%s : %s" % (now, message)



class StoppableThread(threading.Thread):

def __init__(self, sleep_time, function, args=[], kwargs={}):

self.sleep_time = sleep_time

threading.Thread.__init__(self)

self.function = function
self.args = args
self.kwargs = kwargs
self.finished = threading.Event()


def run(self):

while not self.finished.isSet(): # loop while condition
is true
log('** Doing Work')
self.function(*self.args, **self.kwargs) # run the function
self.finished.wait(self.sleep_time) # put thread in wait
state


log('** Thread Has STOPPED!')


def stop(self): # stop the thread from running
log('* Stopping Thread')
self.finished.set()
self.join()




def my_function (a, b, c):
log('my_function running... %s' % a)


#####################################################################
# T E S T
#####################################################################

SMALL_SLEEP = 35
CHECK_SLEEP = 300 # sleep interval in seconds to run a timed
process


log('Create Thread')
thread_obj = StoppableThread(CHECK_SLEEP, my_function, (15,0,-1))


log('Thread Start\n')
thread_obj.start()

for current_loop in range(0,10):
time.sleep(SMALL_SLEEP)
log('current loop = %d \n' % current_loop)

log('Call Thread Stop')
thread_obj.stop()

log('Done!')


Test Output :
python Simple_Thread_Stop_Event.py

12:58:42 : Create Thread
12:58:42 : Thread Start

12:58:42 : ** Doing Work
12:58:42 : my_function running... 15
12:59:17 : current loop = 0
12:59:52 : current loop = 1
13:00:27 : current loop = 2
13:01:02 : current loop = 3
13:01:37 : current loop = 4
13:02:12 : current loop = 5
13:02:47 : current loop = 6
13:03:22 : current loop = 7
13:03:42 : ** Doing Work
13:03:42 : my_function running... 15
13:03:57 : current loop = 8

13:04:32 : current loop = 9

13:04:32 : Call Thread Stop
13:04:32 : * Stopping Thread
13:04:32 : ** Thread Has STOPPED!
13:04:32 : Done!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top