Timeout for Thread.Join()

Understanding thread.join(timeout)

You're misunderstanding what timeout does. It just tells join how long to wait for the thread to stop. If the thread is still running after the timeout expires, the join call ends, but the thread keeps running.

From the docs:

When the timeout argument is present and not None,
it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call isAlive() after join() to decide whether a timeout happened – if the thread is still alive, the join() call timed out.

python multi-thread join with timeout

Yes, you can calculate an absolute timeout, and recompute your remaining relative timeout before every join:

# Join the_threads, waiting no more than some_relative_timeout to
# attempt to join all of them.

absolute_timeout = time.time() + some_relative_timeout

for thr in the_threads:
timeout = absolute_timeout - time.time()
if timeout < 0:
break
thr.join(timeout)
if thr.isAlive():
# we timed out
else:
# we didn't

Now, whether or not you *should* do this is a bit opaque. It may be better to have "daemon" worker threads communicate their completion by other means: a global state table, pushes of "done" messages to a queue, etc.

Python thread.join(timeout) not timing out

I suspect in this case you're hitting an issue where the join can't execute while the global interpreter lock is held by the very long-running calculation, which I believe would happen as a single atomic operation. If you change longFunc to something that happens over multiple instructions, such as a busy loop, e.g.

def longFunc():
while True:
pass

then it works as expected. Is the single expensive calculation realistic for your situation or did the example just happen to hit a very bad case?

Using the multiprocessing module does appear to resolve this issue:

from multiprocessing import Process

def longFunc():
# this expression could be entered by the user
return 45 ** 10 ** 1000

if __name__ == "__main__":
thread = Process(target=longFunc, args=(), daemon=True)
thread.start()
thread.join(5.0)
print("end")

This prints "end" as expected.

Join a group of threads with overall timeout

First create a single CountDownLatch having a count for every thread in the group.

A controlling thread can await(timeout, TimeUnit) on the latch.

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html#await-long-java.util.concurrent.TimeUnit-

Start the threads that are in the group.

Each of the threads in the group should decrement the latch when it completes.

The controlling thread will wait until everything in the group has completed or the timeout happens, and because await returns a boolean, the controlling thread can tell whether the latch was decremented naturally or whether a timeout occurred.

Python - Join Multiple Threads With Timeout

You could loop over each thread repeatedly, doing non-blocking checks to see if the thread is done:

import time

def timed_join_all(threads, timeout):
start = cur_time = time.time()
while cur_time <= (start + timeout):
for thread in threads:
if not thread.is_alive():
thread.join()
time.sleep(1)
cur_time = time.time()

if __name__ == '__main__':
for thread in threads:
thread.start()

timed_join_all(threads, 60)

Python how to detect if a thread join timed out

The intention of t.join(5) is for your main thread to wait up to 5 seconds for your worker thread t to finish naturally.

So, if the timeout expires, that means the thread didn't finish during that time. In other words the thread will still be alive and running after the join operation - which you can detect using t.isAlive(). https://docs.python.org/2/library/threading.html#thread-objects

Timeout for thread.join()

There is no timeout for std::thread::join(). However you can view std::thread::join() as merely a convenience function. Using condition_variables you can create very rich communication and cooperation between your threads, including timed waits. For example:

#include <chrono>
#include <thread>
#include <iostream>

int thread_count = 0;
bool time_to_quit = false;
std::mutex m;
std::condition_variable cv;

void f(int id)
{
{
std::lock_guard<std::mutex> _(m);
++thread_count;
}
while (true)
{
{
std::lock_guard<std::mutex> _(m);
std::cout << "thread " << id << " working\n";
}
std::this_thread::sleep_for(std::chrono::milliseconds(250));
std::lock_guard<std::mutex> _(m);
if (time_to_quit)
break;
}
std::lock_guard<std::mutex> _(m);
std::cout << "thread ended\n";
--thread_count;
cv.notify_all();
}

int main()
{
typedef std::chrono::steady_clock Clock;
std::thread(f, 1).detach();
std::thread(f, 2).detach();
std::thread(f, 3).detach();
std::thread(f, 4).detach();
std::thread(f, 5).detach();
auto t0 = Clock::now();
auto t1 = t0 + std::chrono::seconds(5);
std::unique_lock<std::mutex> lk(m);
while (!time_to_quit && Clock::now() < t1)
cv.wait_until(lk, t1);
time_to_quit = true;
std::cout << "main ending\n";
while (thread_count > 0)
cv.wait(lk);
std::cout << "main ended\n";
}

In this example main launches several threads to do work, all of which occasionally check if it is time to quit under a mutex (this could also be an atomic). The main thread also monitors if it is time to quit (if the threads get all their work done). If main runs out of patience, he just declares it to be time to quit, then waits for all threads to perform any necessary clean up before exiting.



Related Topics



Leave a reply



Submit