Jean Coiron
Jean Coiron

Reputation: 632

how to automatically release a semaphore in a thread after run() is executed?

I'm tracking the number of threads through a semaphore this way :

#!/usr/bin/python3
import threading

class MyThread(threading.Thread):

    max_threads           = 5
    max_threads_semaphore = threading.BoundedSemaphore(value=max_threads)
    semaphore_timeout     = 60 

    def __init__(self, target=None, name=None, args=(), kwargs={}):
        super().__init__(target=target, name=name, args=args, kwargs=kwargs)

    def start(self):
        semaphore_aquired = self.max_threads_semaphore.acquire(blocking=True, timeout=self.semaphore_timeout)
        if semaphore_aquired:
            print("Sempahore acquired by:", self.name)
            super().start()
        else:
            raise OSError("Time out aquiring max threads semaphore to start new thread")

    def join(self):
        super().join()
        semaphore_released = self.max_threads_semaphore.release()

This work, but not the way I want. I want to be able to :

def print_test(num):
    print("executing:", num)
    sleep(10)
    print("end of execution:", num)

threads_dict = dict()
thread_range = range(1,20)
for i in thread_range:
    threads_dict[i] = MyThread(target=print_test(i))
    threads_dict[i].start()
for i in thread_range:
    threads_dict[i].join()
    print("joined:", threads_dict[i].name)

Obviously, once 5 threads are started (max_threads), the script is in deadlock until the semaphore timeout is reached.

I thought that the start() method would launch the run() method in a new thread. From the manual :

start() It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.

So in MyThread I replaced the join() part with :

def run(self):
    super().run()
    semaphore_released = self.max_threads_semaphore.release()
    print("Sempahore released by:", self.name)

But this code is not executed in a new thread. Output is :

executing: 1
end of execution: 1
Sempahore acquired by: Thread-1
Sempahore released by: Thread-1
executing: 2
end of execution: 2
Sempahore acquired by: Thread-2
Sempahore released by: Thread-2
executing: 3
end of execution: 3
Sempahore acquired by: Thread-3
Sempahore released by: Thread-3
executing: 4
end of execution: 4
Sempahore acquired by: Thread-4
Sempahore released by: Thread-4
executing: 5
end of execution: 5
Sempahore acquired by: Thread-5
Sempahore released by: Thread-5
executing: 6
end of execution: 6
Sempahore acquired by: Thread-6
executing: 7
Sempahore released by: Thread-6
end of execution: 7
Sempahore acquired by: Thread-7
executing: 8
Sempahore released by: Thread-7
end of execution: 8
Sempahore acquired by: Thread-8
executing: 9
Sempahore released by: Thread-8
end of execution: 9
Sempahore acquired by: Thread-9
joined: Thread-1
joined: Thread-2
joined: Thread-3
joined: Thread-4
joined: Thread-5
joined: Thread-6
joined: Thread-7
joined: Thread-8
Sempahore released by: Thread-9
joined: Thread-9

Is there a way to overload a threading.Thread function in order to automatically release the semaphore when the target function ends ?

I don't understand why the output is not :

Sempahore acquired by: Thread-1
executing: 1
Sempahore acquired by: Thread-2
executing: 2
Sempahore acquired by: Thread-3
executing: 3
Sempahore acquired by: Thread-4
executing: 4
Sempahore acquired by: Thread-5
executing: 5
(sleep 10 secondes)
end of execution: 1
Sempahore released by: Thread-1
Sempahore acquired by: Thread-6
executing: 6
etc..

Upvotes: 0

Views: 1332

Answers (1)

user2725093
user2725093

Reputation: 221

As for question about "strange" output. That is expectedly because you call print_test(i) in main thread before creating new thread:

threads_dict[i] = MyThread(target=print_test(i))

This is executing of print_test(i) function. And as result you past to target result of print_test(i) function execution.

Try to correct this:

threads_dict[i] = MyThread(target=print_test, args=[i,])

After this correction I have output like:

('Sempahore acquired by:', 'Thread-1')
('Sempahore acquired by:', 'Thread-2')
('executing:', 1)
('Sempahore acquired by:', 'Thread-3')
('executing:', 2)
('Sempahore acquired by:', 'Thread-4')
('executing:', 3)
('Sempahore acquired by:', 'Thread-5')
('executing:', 4)
('executing:', 5)
('end of execution:', 1)
('Sempahore released by:', 'Thread-1')
('Sempahore acquired by:', 'Thread-6')
...

Upvotes: 1

Related Questions