C++多线程简介(+源码实例)

C++20

出于方便更新的考虑,文章位于GITEE仓库。仓库的地址是https://gitee.com/az13js/about-cpp

多线程

线程是指一个程序中的一条单一的执行流,包括最高层函数的调用和递归调用的每一个函数。多线程是指允许一个程序里存在多个线程。也就是多线程的程序可以在同一时间执行多个计算过程,而单一线程的程序只能顺序执行多个计算过程,所以多线程的程序比单一线程的执行速度快(在多核处理器上才有这种效果)。

多线程里面比较常用的概念是join和detach。join是指阻塞进程直到join的线程执行完,言外之意执行流A创建线程B,接着对B进行join,然后A就暂停直到B执行完成后A再继续执行。detach的作用是将子线程和主线程的关联分离,detach后子线程在后台独立继续运行,主线程无法再取得子线程的控制权,即使主线程结束,子线程未执行也不会结束。

C++跟多线程有关的部分主要是两个类,threadjthread,其中jthread是对thread的封装。通过thread类可以创建并管理线程,而且一个thread类的实例就是实际上的一条线程。使用threadjthread需要#include <thread>,注意要使用命名空间std,因为这两个类都在std下。

C++的设计里thread或者jthread对象并不完全等价于计算机中真执行的线程,只是说thread或jthread暂时关联了真正的线程,而这个关联关系是可以调整的。

C++中的thread

thread类是C++11开始提供的,下面的代码创建一条线程并在线程内打印文字内容。

通过join()方法

#include <iostream>
#include <thread>

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;
}

编译并执行会先后输出HelloHi

$ g++ -std=c++20 test.cpp -lpthread
$ ./a.out
Hello
Hello
Hello
Hi
Hi
Hi

通过detach()方法,主线程不阻塞。

#include <iostream>
#include <thread>

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同时在运行。

C++20新加入的jthread

由于在早前版本的C++中并没有提供jthread,所以要使用支持C++20的编译器才能顺利编译使用jthread类的代码。下面是使用GCC 10进行测试的结果。

文件test.cpp

#include <thread>

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. std::jthread 对象被 destruct 时,会自动调用 join,等待其所表示的执行流结束。
  2. 支持外部请求中止(通过 get_stop_source、get_stop_token 和 request_stop )。

下面的程序可以验证第1点。

#include <iostream>
#include <thread>

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 <iostream>
#include <thread>

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<class F, class... Args> explicit thread(F&& f, Args&&... args);

所以第一个参数是函数的指针,后面的参数作为函数的参数传递了。jthread类似。

参考材料

  1. C++20 多线程 std::jthread
  2. 【C/C++开发】多线程编程中的join函数
  3. C++ 中多线程中join 的作用
  4. C++ std::thread 和 std::jthread 使用详解 (含C++20新特性)
  5. 多线程 参数传递
  6. C++ std::thread
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值