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_variable
s 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
Locking Files in Linux with C/C++
Reading Files Larger Than 4Gb Using C++ Stl
How to Determine Sizeof Class with Virtual Functions
What Does the & (Ampersand) at the End of Member Function Signature Mean
Generate N Random Numbers Within a Range with a Constant Sum
Mapping Elements in 2D Upper Triangle and Lower Triangle to Linear Structure
C++ 128/256-Bit Fixed Size Integer Types
Why Does 'Std::Basic_Ifstream<Char16_T>' Not Work in C++11
Double Dispatch/Multimethods in C++
Conditionally Replace Regex Matches in String
How to Assign a Value to the Pointer 'This' in C++
How Is If Statement Evaluated in C++
Can a Copy-Constructor Take a Non-Const Parameter
How to Call the Class's Destructor
C++ Logon Task Schedule Error: No Mapping Between Account Names and Security Ids Was Done