GP89
GP89

Reputation: 6740

Creating a 'singleton' thread- How to have at most 1 instance of a thread at any one time

I'm looking to have a class (subclassed from threading.Thread) that is initialised and started from multiple places in a program. What I want to avoid is if the thread is already running from somewhere else, if another place in the program trys to start it

t= somemodule.TheThread(some,args)
t.start()

the program can carry on (but the thread only starts if the same thread isn't already running here, or elsewhere).

I can think of a few not very elegant ways to achieve this with setting flags, but there must be a nice way of dealing with this. I looked at singleton type patterns with decorators or overriding new but the main problem is that if I keep the same instance is that you can't (that I'm aware) call start more than once, even if the thread has finished.

I thought about having the thread object created in anther object which can check to see if the current thread is still running, but I couldn't work out how to keep this thread safe.

Anyone got any ideas?

Upvotes: 2

Views: 1291

Answers (3)

Martin James
Martin James

Reputation: 24907

Start the thread at app startup and have it wait on an event. If the event gets set, the thread does its work, resets the event and waits on it again. Once some other thread 'starts' the loop-thread by setting the event, any number of other threads can call 'set' to no effect until the loop-thread has done its work, cleared the event and is waiting again.

No thread micro-management, no possibility of there ever being more than one thread instance, no thread-unsafety, no flags, no dubious thread-state checking.

There is a small window between the loop-thread finishing its work and clearing the event where a set from another thread will be ignored. Such uncertainty is difficult to eliminate with the design you have chosen. You could use a semaphore instead of an event and use a acquire(false) loop at the top to both check if the semaphore has been signaled and also to ensure its count is zero again. If the semaphore has been signaled, the thread can run its work again. If the semaphore has not been signaled, it can be waited on until it is.

Upvotes: 0

jcollado
jcollado

Reputation: 40424

One easy way to check if a somemodule.TheThread thread is alive is as follows:

any(isinstance(thread, somemodule.TheThread)
    for thread in threading.enumerate())

Upvotes: 0

Ned Batchelder
Ned Batchelder

Reputation: 376052

You should use a function to create and start the thread, and that function can use its own bookkeeping to know whether the thread has been started already or not. Don't forget to make that bookkeeping thread-safe!

Trying to make the caller believe he is creating and starting a thread, when maybe he isn't, is more trouble than it is worth. Encapsulating this common operation in a function is a good idea in any case, and gives you the control you're seeking.

Upvotes: 6

Related Questions