Reputation: 12531
I have a vector
of thread
s in my C++ program.
std::vector<std::thread> threadList;
I then create a thread and push it into the vector
.
threadList.push_back(std::thread([]() { ... }));
How can I remove the thread
from the threadList
vector
when the lambda function finishes execution?
Edit
I've come up with somewhat of a solution; Before the thread lambda function returns, it iterates through the vector
to find a match in ID with this_thread::get_id()
.
Through Visual Studio debugging line by line, I see that it finds a match in ID and the erase function is executed, but as soon as threadList.erase(threadList.begin() + index);
is executed, I come accross an unhandled exception at the thread's deconstructor function.
I've written a small piece of code which replicates this error.
vector<thread> threadList;
threadList.push_back(thread([]() {
Sleep(1000);
threadList.erase(threadList.begin());
}));
Sleep(2000);
//for_each(threadList.begin(), threadList.end(), mem_fn(&thread::detach));
//threadList.clear();
This code results in the screenshot below.
Upvotes: 4
Views: 5111
Reputation: 597670
One option is to have the lambda remove the thread asynchronously when exiting. For example:
std::vector<std::thread> threadList;
std::mutex threadMutex;
...
void removeThread(std::thread::id id)
{
std::lock_guard<std::mutex> lock(threadMutex);
auto iter = std::find_if(threadList.begin(), threadList.end(), [=](std::thread &t) { return (t.get_id() == id); });
if (iter != threadList.end())
{
iter->detach();
threadList.erase(iter);
}
}
...
{
std::lock_guard<std::mutex> lock(threadMutex);
threadList.push_back(
std::thread([]() {
...
std::async(removeThread, std::this_thread::get_id());
})
);
}
Alternatively:
std::vector<std::thread> threadList;
std::mutex threadMutex;
...
void removeThread(std::thread::id id)
{
std::lock_guard<std::mutex> lock(threadMutex);
auto iter = std::find_if(threadList.begin(), threadList.end(), [=](std::thread &t) { return (t.get_id() == id); });
if (iter != threadList.end())
{
iter->join();
threadList.erase(iter);
}
}
...
{
std::lock_guard<std::mutex> lock(threadMutex);
threadList.push_back(
std::thread([]() {
...
std::thread(removeThread, std::this_thread::get_id()).detach();
})
);
}
Alternatively:
std::vector<std::thread> threadList;
std::mutex threadMutex;
std::list<std::thread::id> threadFreeList;
std::mutex threadFreeMutex;
std::condition_variable threadFreeCV;
std::thread monitor([]() {
while (... /* app is not terminated */)
{
std::unique_lock<std::mutex> lock(threadFreeMutex);
threadFreeCV.wait(lock);
std::lock_guard<std::mutex> lock2(threadMutex);
auto iter = threadFreeList.begin();
while (iter != threadFreeList.end())
{
auto id = *iter;
auto found = std::find_if(threadList.begin(), threadList.end(), [=](std::thread &t) { return (t.get_id() == id); });
if (found != threadList.end())
{
found->join();
threadList.erase(found);
}
iter = threadFreeList.erase(iter);
}
}
});
...
{
std::lock_guard<std::mutex> lock(threadMutex);
threadList.push_back(
std::thread([]() {
...
std::unique_lock<std::mutex> lock(threadFreeMutex);
threadFreeList.push_back(std::this_thread::get_id());
threadFreeCV.notify_one();
})
);
}
Upvotes: 4
Reputation: 9423
Why do you need this vector of threads when you can detach them?
// Scope that outlives the threads
boost::barrier out_barrier(N_threads+1);
...
// Starting the threads
for(int i = 0; i < N_threads; i++) {
std::thread th([&out_barrier]() {
...do the job...
out_barrier.wait();
});
th.detach();
}
...
// Wait for threads to finish
out_barrier.wait();
The threads are not joinable so it's safe to call the destructor. The synchronization is unavoidable in this case. In my example, it's used to join all threads and if you have a vector of threads you will need to synchronize the access to the vector so it's all the same.
Upvotes: 0