出于方便更新的考虑,文章位于GITEE仓库。仓库的地址是https://gitee.com/az13js/about-cpp
线程是指一个程序中的一条单一的执行流,包括最高层函数的调用和递归调用的每一个函数。多线程是指允许一个程序里存在多个线程。也就是多线程的程序可以在同一时间执行多个计算过程,而单一线程的程序只能顺序执行多个计算过程,所以多线程的程序比单一线程的执行速度快(在多核处理器上才有这种效果)。
多线程里面比较常用的概念是join和detach。join是指阻塞进程直到join的线程执行完,言外之意执行流A创建线程B,接着对B进行join,然后A就暂停直到B执行完成后A再继续执行。detach的作用是将子线程和主线程的关联分离,detach后子线程在后台独立继续运行,主线程无法再取得子线程的控制权,即使主线程结束,子线程未执行也不会结束。
C++跟多线程有关的部分主要是两个类,thread
和jthread
,其中jthread
是对thread
的封装。通过thread
类可以创建并管理线程,而且一个thread
类的实例就是实际上的一条线程。使用thread
或jthread
需要#include
,注意要使用命名空间std
,因为这两个类都在std
下。
C++的设计里thread或者jthread对象并不完全等价于计算机中真执行的线程,只是说thread或jthread暂时关联了真正的线程,而这个关联关系是可以调整的。
thread
类thread
类是C++11开始提供的,下面的代码创建一条线程并在线程内打印文字内容。
join()
方法#include
#include
using namespace std;
void myThreadFunction() {
for (int i = 0; i < 3; i++) {
cout << "Hello" << endl;
}
}
int main()
{
thread myThreadObject = thread(myThreadFunction);
myThreadObject.join();
for (int x = 0; x < 3; x++) {
cout << "Hi" << endl;
}
return 0;
}
编译并执行会先后输出Hello
和Hi
:
$ g++ -std=c++20 test.cpp -lpthread
$ ./a.out
Hello
Hello
Hello
Hi
Hi
Hi
detach()
方法,主线程不阻塞。#include
#include
using namespace std;
void myThreadFunction() {
for (int i = 0; i < 3; i++) {
cout << "Hello" << endl;
}
}
int main()
{
int tmp;
thread myThreadObject = thread(myThreadFunction);
myThreadObject.detach();
for (int x = 0; x < 3; x++) {
cout << "Hi" << endl;
}
cin >> tmp;
return 0;
}
编译方法与上面的join()
例子一样,最后输出类似:
$ ./a.out
Hi
Hi
Hi
Hello
Hello
Hello
随便输入一个字符并回车退出程序。根据实际情况输出的内容顺序可能不一样,因为这时主函数跟myThreadFunction
同时在运行。
jthread
类由于在早前版本的C++中并没有提供jthread
,所以要使用支持C++20的编译器才能顺利编译使用jthread
类的代码。下面是使用GCC 10
进行测试的结果。
文件test.cpp
:
#include
using namespace std;
int main()
{
jthread t;
return 0;
}
编译命令:
g++ -std=c++20 test.cpp
执行后生成了文件a.out
。
jthread
类使用与thread
类差不多,差别参考C++ std::thread 和 std::jthread 使用详解 (含C++20新特性)
下面的程序可以验证第1点。
#include
#include
using namespace std;
void myThreadFunction() {
for (int i = 0; i < 3; i++) {
cout << "Hello" << endl;
}
}
int main()
{
jthread* myThreadObject = new jthread(myThreadFunction);
delete myThreadObject; // 内部自动调用 join()
for (int i = 0; i < 3; i++) {
cout << i << endl;
}
return 0;
}
程序输出总会是:
Hello
Hello
Hello
0
1
2
例子,main
函数传递参数给它创建出来的线程。
#include
#include
using namespace std;
void myThreadFunction(int* array, int length) {
int len = length;
int* arr = array;
for (int i = 0; i < len; i++) {
cout << arr[i] << endl;
}
}
int main()
{
int a[] = {1, 2, 3};
int len = 3;
jthread myThreadObject = jthread(myThreadFunction, a, len);
return 0;
}
参考C++标准,thread
声明:
template explicit thread(F&& f, Args&&... args);
所以第一个参数是函数的指针,后面的参数作为函数的参数传递了。jthread
类似。