Reputation: 79
I have a vector of threads that I collect during the execution of my application. To avoid some nasty behavior, I'm trying to ensure every thread is completed when the main thread exits. I tried to call std::thread::join
on each thread in the vector upon a termination event, but it seems to get stuck if the most recent thread hasn't finished its work and won't stop blocking even after it should. It's important to note that ThingMaker::CreateThing
reads frames from a series of video files and writes them all to one video, so I know the thread should finish its work in less time than the length of the video clip being created.
std::vector<std::thread> threadList;
while (!done)
{
switch (triggerEvent)
{
case 'h': // Spawn new thread to make a thing "in the background"
{
ThingMaker next_thing = new ThingMaker();
threadList.push_back(std::thread(&ThingMaker::CreateThing, next_thing));
next_thing = NULL;
break;
}
case 't': // Terminate the application
{
std::vector<std::thread>::iterator threads;
for (threads = threadList.begin(); threads != threadList.end(); ++threads)
threads->join();
done = true;
break;
}
default: break;
}
}
If I send a 't' before the most recent thread has finished making the video clip and thus finished altogether, threads->join()
blocks forever. However, if i wait for all video clips to be created, the application terminates. To my understanding, it should simply wait for the thread to finish its work and then let the main thread carry on - is this a misunderstanding?
Upvotes: 1
Views: 2253
Reputation: 171383
The code you have shown (which is still woefully incomplete and so we're just guessing) doesn't remove thread
objects from the vector after you join them. That means you will try to rejoin an already joined thread on the next time through the loop. Trying to join a thread that is not joinable has undefined behaviour. It could block forever (because there is no such thread so it can never be joined).
You should either:
only try to join threads that are joinable:
case 't': // Terminate the application
{
for (auto& t : threadList)
if (t.joinable())
t.join();
done = true;
break;
}
or remove the threads from the list after they've been joined:
case 't': // Terminate the application
{
for (auto& t : threadList)
t.join();
threadList.clear();
done = true;
break;
}
Upvotes: 0
Reputation: 182829
There are two possibilities:
The thread simply hasn't finished yet. You can add logging to your code or use a debugger to see whether this is the case.
The thread that called join
holds some lock that is preventing the other thread from finishing. Calling join
waits for a thread to finish and cannot be safely called unless you're absolutely sure that thread that calls join
holds no locks the other thread might need to acquire in order to finish. (Look closely at the call stack leading to the call to join
to see if this is a posssibility.)
Upvotes: 3
Reputation: 73456
There are two issues in your code:
The join()
on an active thread will wait that the thread is finished before continuing anything. So if you have no mechanism to to tell your threads to stop (e.g. a shared atomic variable), you'll wait forever.
Your threadlist
vector is inside the while loop, so that it's a new list on every occurence. What happens to the thread that you have pushed into it ? It gets destroyed, and as join()
wasn't called, it will terminate()
your programme.
Upvotes: 3
Reputation: 27038
With std::thread
you must ensure that each thread is made unjoinable (that typically means calling .join()), exactly once. Clearly, a call to .join()
will wait for that thread to complete. Start a debug session and have a look what each of the threads are doing.
Upvotes: 1