
在本章开头的小节里面我们介绍了如何创建线程但是很少有人会注意到创建的线程如何确保一定运行起来了很多人会说对于使用系统 API 创建的线程只需要判断一下创建的线程函数是否是调用成功的这只做了一步线程函数调用成功也没法百分百保证线程函数一定运行起来了。在一些“古老”或者“严谨”的项目中你会发现这些代码创建线程时不仅判断线程创建函数是否调用成功还会在线程函数中利用上文介绍的一些线程同步对象来通知线程的创建者线程是否创建成功。我们来看一段这样的代码#include thread #include mutex #include condition_variable #include iostream std::mutex mymutex; std::condition_variable mycv; bool success false; void thread_func() { { std::unique_lockstd::mutex lock(mymutex); success true; mycv.notify_all(); } //实际的线程执行的工作代码放在下面 //这里为了模拟方便简单地写个死循环 while (true) { } } int main() { std::thread t(thread_func); //使用花括号减小锁的粒度 { std::unique_lockstd::mutex lock(mymutex); while (!success) { mycv.wait(lock); } } std::cout start thread successfully. std::endl; t.join(); return 0; }上述代码发出一个创建新线程的请求后立刻阻塞在一个条件变量上工作线程如果成功运行起来会发送条件变量信号告知主线程这样主线程就知道新线程一定成功运行起来了。基于以上思路我们创建一组线程时可以一个地创建每成功运行一个新线程再创建下一个确保线程组中的每一个线程都可以运行起来。示例代码如下#include thread #include mutex #include condition_variable #include iostream #include vector #include memory std::mutex mymutex; std::condition_variable mycv; bool success false; void thread_func(int no) { { std::unique_lockstd::mutex lock(mymutex); success true; mycv.notify_all(); } std::cout worker thread started, threadNO: no std::endl; //实际的线程执行的工作代码放在下面 //这里为了模拟方便简单地写个死循环 while (true) { } } int main() { std::vectorstd::shared_ptrstd::thread threads; for (int i 0; i 5; i) { success false; std::shared_ptrstd::thread spthread; spthread.reset(new std::thread(thread_func, i)); //使用花括号减小锁的粒度 { std::unique_lockstd::mutex lock(mymutex); while (!success) { mycv.wait(lock); } } std::cout start thread successfully index: i std::endl; threads.push_back(spthread); } for (auto iter : threads) { iter-join(); } return 0; }编译上述程序并运行运行结果如下所示[rootmyaliyun codes]# g -g -o makesurethreadgroup makesurethreadgroup.cpp -stdc0x -lpthread [rootmyaliyun codes]# ./makesurethreadgroup worker thread started, threadNO: 0 start thread successfully index: 0 worker thread started, threadNO: 1 start thread successfully index: 1 worker thread started, threadNO: 2 start thread successfully index: 2 worker thread started, threadNO: 3 start thread successfully index: 3 worker thread started, threadNO: 4 start thread successfully index: 4可以看到新线程挨个运行起来。当然你不一定要使用条件变量也可以使用其他类型的线程同步对象如 Windows 平台的 Event 对象等等。按照行文逻辑这一节应该放在创建线程那一节介绍但是由于这里使用到了线程同步对象所以这里的内容移到了介绍完各种线程资源同步对象之后来介绍。不知道读者注意到没有我在介绍上述说的确保线程一定运行起来的做法时使用了两个词——“古老”和“严谨”“严谨”不用多介绍之所以说“古老”是因为你现在在各种新型的项目中基本上再也看不到这种确保线程运行起来的做法了许多年以前多线程编程开始流行起来的时候那时由于软硬件的水平限制加之很多开发人员对多线程编程技术的不熟悉创建新线程时确保一个线程跑起来非常必要而如今多线程编程已经如此的司空见惯加上操作系统和 CPU 普遍对多线程技术的支持我们再也不用写这样的“防御“代码了甚至只要你正确使用线程创建函数我们实际编码时连线程函数的返回值都不必判断基本上可以认为新线程一定会创建成功且线程可以正常跑起来。