一、概述
在C++中,多线程编程已成为常见的编程模式。然而,多线程编程有一个较为困难的问题:如何保证多个线程的执行顺序,确保某个线程在需要时能够等待其他线程的结束?本文将介绍一些技巧和方法,以解决这些问题,使得多个线程能够协调有序地执行。
二、使用std::thread::join方法等待线程结束
C++11中引入了std::thread类,使得线程的创建和管理变得更加容易。其中,join方法可用来等待线程结束。该方法将阻塞直到线程运行结束为止。下面是一个例子:
#include <iostream>
#include <thread>
void threadFunc()
{
std::cout << "thread function executing" << std::endl;
}
int main()
{
std::thread t(threadFunc);
std::cout << "main thread executing" << std::endl;
t.join();
std::cout << "thread terminated" << std::endl;
}
在该例子中,首先创建了一个线程t,并调用了它的join方法。在调用join方法之前,线程t的函数threadFunc被执行。join方法的执行将阻塞当前线程(即主线程),直到线程t执行结束。线程t结束后,程序继续执行,输出 "thread terminated"。 需要注意的是,每个线程只能被join一次,第二次调用join方法将导致未定义行为。
三、使用std::thread::detach方法将线程和主线程分离
另外一种等待线程结束的方法是使用std::thread::detach方法。当线程被分离后,其生命周期将不再由主线程控制。该方法的调用将立即返回,不会阻塞当前线程。下面是一个例子:
#include <iostream>
#include <thread>
void threadFunc()
{
std::cout << "thread function executing" << std::endl;
}
int main()
{
std::thread t(threadFunc);
std::cout << "main thread executing" << std::endl;
t.detach();
std::cout << "thread detached" << std::endl;
return 0;
}
在该例子中,线程t被创建,然后调用detach方法将其分离。由于线程t已经被分离,不再受主线程的控制,因此主线程在完成自身任务后,将立即退出。因此,在该例子中并没有输出 "thread function executing"。 但是需要注意的是,当线程被分离后,它的资源(例如堆栈)将不再被自动释放,必须手动释放。
四、使用std::promise和std::future
如果需要某个线程的结果数据,可以使用std::promise和std::future来实现等待线程结束并获取结果的效果。std::promise是一个可以与std::future配合使用的类模板,它的作用是给线程一个“承诺”,立即返回一个与之相关联的std::future对象。std::future对象是一个可以用来访问“承诺”的对象,它提供了等待“承诺”完成并获取结果的方法。 下面是一个例子:
#include <iostream>
#include <thread>
#include <future>
void threadFunc(std::promise<int>& p)
{
std::cout << "thread function executing" << std::endl;
p.set_value(42);
}
int main()
{
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread t(threadFunc, std::ref(p));
std::cout << "main thread executing" << std::endl;
int result = f.get();
std::cout << "result=" << result << std::endl;
t.join();
return 0;
}
在该例子中,首先创建了一个std::promise对象p,并调用它的get_future方法得到一个std::future对象f。然后创建了一个线程t,并将p作为参数传给线程。在线程函数threadFunc中,将结果值42存入p,主线程调用f的get方法等待线程t的结果。当线程t执行结束后,程序继续执行,输出结果。
五、使用std::condition_variable等待线程结束
std::condition_variable是一个同步原语,可以用来在多个线程之间进行等待和通知。当条件不满足时,线程可以通过wait方法阻塞;当条件满足时,线程可以通过notify_one或notify_all方法进行通知。使用std::condition_variable可以等待多个线程的运行结束,从而达到等待多个线程结束的效果。 下面是一个例子:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
std::mutex mtx;
std::condition_variable cv;
void threadFunc(int id)
{
std::unique_lock<std::mutex> lck(mtx);
std::cout << "thread " << id << " executing" << std::endl;
cv.notify_one();
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i)
{
threads.emplace_back(threadFunc, i + 1);
}
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [&]() { return threads.empty(); });
std::cout << "all threads terminated" << std::endl;
return 0;
}
在该例子中,首先创建了5个线程,并将它们的ID作为参数传递给线程函数threadFunc。在线程函数中,输出线程的ID并通知等待的线程。在主线程中,等待所有线程执行结束。在等待的过程中,主线程通过wait方法阻塞,直到所有线程都执行结束,等待期间condition_variable会释放锁。当条件满足时,主线程继续执行,输出 "all threads terminated"。
六、总结
本文介绍了多种等待C++多线程结束的方法,包括使用std::thread::join方法、使用std::thread::detach方法、使用std::promise和std::future以及使用std::condition_variable等待线程结束。选择合适的方法可以使得多线程编程更加高效而容易。