使用C++多线程
使用平台为Windows,使用多线程时需要包含thread头文件。
第一个多线程程序:循环打印一个话。
1 |
|
欲要使用多线程,先声明了一个thread对象,并用FirstThread来进行初始化,当线程执行时就会执行FirstThread函数。
将线程启动有两种方式,第一种是使用join函数,join会阻塞当前线程的执行,当子线程执行完毕后才会继续执行;第二种是detach函数,他将函数的执行与主线程分离。
本例的一些问题:
- 使用detach时,当主线程退出后子线程不一定会退出,可能还在执行。
- main结束后清理空间,此时子线程可能会访问非法内存,本例中使用getchar阻塞线程来避免这种情况。
带有参数的多线程
上述例子中使用了一个简单的函数,对于带参数的函数使用方法是类似的,只需要在创建thread时带上参数即可,不过不同的参数类型需要的方法会有一些差异。
带有普通参数
对于普通参数直接将实参代入thread对象中即可。
提供以下测试:
1 | void ThreadWithParam(int param_1,char param_2) |
对于指针和引用
对于普通参数的使用还是很简单的,对于指针和引用,只需要在创建thread对象时稍加修改:
这里创建一个param类来作为参数类型
1 | class Param |
将上述代码执行后,对于引用部分,可以发现构造函数/析构函数被执行了三次!
额外的两次开销分别在传递时创建了一次,到函数中拷贝了副本又执行了一次,总共三次。
为了避免这种情况,只需要对th2稍加修改,使用Ref修饰参数即可:
1 | //thread th2(ThreadWithRefParam,p2); |
此时再次执行th2只会构造一次。
将类作为线程入口
上面的例子是直接将函数作为入口,接下来将类成员函数作为入口。
一般设计
给上例中的Param增加一个成员函数Func(),并作为线程入口:
1 | class Param |
本例比较简单,直接将成员函数的地址以及对象提供给thread对象即可。
将入口进行封装
现考虑设计如下类:
- 使用成员函数作为线程入口。
- 使用一个线程基类,需要使用的地方继承此类。
- 提供一个逻辑入口,在使用的类重载一份实现。
为了满足上述要求,设计如下线程基类:
- 提供一个BaseThread类,需要多线程的类继承该类。
- 提供一个ThreadBegin函数作为线程入口。
- 提供一个Main函数作为逻辑入口。
- 为了拥有终止线程的能力,提供一个bool变量来作为终止条件。
- 为了保证Main函数能被继承者实现,将Main声明为纯虚。
给出Base的具体实现:
1 | class BaseThread |
实现一个继承自Base的子类来实现线程类:
1 | class ChildThread:public BaseThread |
对类进行测试;
1 | void test() |
其他调用多线程的方法
使用lambda表达式作为入口
1 | void test() |
在类中使用lambda表达式
使用方法与上述基本相似,不过需要捕获作用域:
1 | class LambdaThread |
总结
以上便是一些线程的调用方法,主要包括:
- 普通函数
- 类成员函数
- 匿名函数
- 本文作者: KongXinQing
- 本文链接: https://13114987559.github.io/2024/03/25/note/C++多线程入门:第一个多线程程序/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!