翻译来自:C++11 Multithreading – Part 2: Joining and Detaching Threads
在本文中,我们将讨论std :: thread的连接和分离。
用std :: thread :: join()连接线程
一旦启动一个线程,则另一个线程可以等待该新线程完成。为此,还需要在std :: thread对象上调用join()函数,即
std::thread th(funcPtr);
// Some Code
th.join();
让我们来看一个例子
假设主线程必须启动10个工作线程,并且在启动所有这些线程之后,主函数将等待它们完成。加入所有线程后,main函数将继续,
#include <iostream>
#include <thread>
#include <algorithm>
class WorkerThread
{
public:
void operator()()
{
std::cout<<"Worker Thread "<<std::this_thread::get_id()<<" is Executing"<<std::endl;
}
};
int main()
{
std::vector<std::thread> threadList;
for(int i = 0; i < 10; i++)
{
threadList.push_back( std::thread( WorkerThread() ) );
}
// Now wait for all the worker thread to finish i.e.
// Call join() function on each of the std::thread object
std::cout<<"wait for all the worker thread to finish"<<std::endl;
std::for_each(threadList.begin(),threadList.end(), std::mem_fn(&std::thread::join));
std::cout<<"Exiting from Main Thread"<<std::endl;
return 0;
}
使用std :: thread :: detach()分离线程
分离的线程也称为守护程序/后台线程。要分离线程,我们需要在std :: thread对象上调用std :: detach()函数,即
std::thread th(funcPtr);
th.detach();
调用detach()之后,std :: thread对象不再与实际的执行线程关联。
在线程句柄上调用detach()和join()时要小心
情况1:永远不要在没有关联执行线程的std :: thread对象上调用join()或detach()
std::thread threadObj( (WorkerThread()) );
threadObj.join();
threadObj.join(); // It will cause Program to Terminate
当在线程对象上调用join()函数时,则当此join(0返回时,则std :: thread对象没有与其关联的线程。如果再次在该对象上调用join()函数,则将导致终止程序。
同样,调用detach()可以使std :: thread对象不与任何线程函数链接。在那种情况下,在std :: thread对象上调用detach(0函数两次)将导致程序终止。
std::thread threadObj( (WorkerThread()) );
threadObj.detach();
threadObj.detach(); // It will cause Program to Terminate
因此,在调用join()或detach()之前,我们应该每次检查线程是否可连接,即
std::thread threadObj( (WorkerThread()) );
if(threadObj.joinable())
{
std::cout<<"Detaching Thread "<<std::endl;
threadObj.detach();
}
if(threadObj.joinable())
{
std::cout<<"Detaching Thread "<<std::endl;
threadObj.detach();
}
std::thread threadObj2( (WorkerThread()) );
if(threadObj2.joinable())
{
std::cout<<"Joining Thread "<<std::endl;
threadObj2.join();
}
if(threadObj2.joinable())
{
std::cout<<"Joining Thread "<<std::endl;
threadObj2.join();
}
情况2 :永远不要忘记在具有关联执行线程的std :: thread对象上调用join或detach
如果在具有关联执行线程的std :: thread对象中 均未调用join或detach,则在该对象的destruct-期间它将-终止程序。 因为在destruct-or里面检查线程是否仍然可以连接,然后终止程序,即
#include <iostream>
#include <thread>
#include <algorithm>
class WorkerThread
{
public:
void operator()()
{
std::cout<<"Worker Thread "<<std::endl;
}
};
int main()
{
std::thread threadObj( (WorkerThread()) );
// Program will terminate as we have't called either join or detach with the std::thread object.
// Hence std::thread's object destructor will terminate the program
return 0;
}
同样,在发生异常的情况下,我们不应忘记调用join()或detach()。为了防止这种情况,我们应该使用“资源获取初始化”(RAII),即
#include <iostream>
#include <thread>
class ThreadRAII
{
std::thread & m_thread;
public:
ThreadRAII(std::thread & threadObj) : m_thread(threadObj)
{
}
~ThreadRAII()
{
// Check if thread is joinable then detach the thread
if(m_thread.joinable())
{
m_thread.detach();
}
}
};
void thread_function()
{
for(int i = 0; i < 10000; i++);
std::cout<<"thread_function Executing"<<std::endl;
}
int main()
{
std::thread threadObj(thread_function);
// If we comment this Line, then program will crash
ThreadRAII wrapperObj(threadObj);
return 0;
}