C++多线程编程(1):线程的创建方式

文章首发于我的个人博客:欢迎大佬们来逛逛

文章目录

  • 进行与线程
  • C++中如何实现多线程
  • 创建线程的多种方式
    • 无参函数
    • lambda表达式
    • 常成员函数
    • not常成员引用函数
    • 智能指针
    • 仿函数
    • 类的普通成员函数
    • 综合测试

进行与线程

多线程是指多个线程并发执行的过程。

进程与线程的关系:

  • 进程是一个独立运行的应用程序
  • 线程是指进程内独立执行的一个单元,一个进程中可能有多个线程。

C++中如何实现多线程

使用 #include <thread> 头文件,里面定义了很多的线程函数。

其中,使用 thread 创建一个线程.

比如我有两个函数,分别是:

  • print1是主线程。
  • 下面四个函数分别是子线程。
void print1() {
	std::cout << "主线程\n";
}
void printtttt1() {
	Sleep(2000);
	std::cout << "子线程1\n";
}
void printtttt2() {
	Sleep(2000);
	std::cout << "子线程2\n";
}
void printtttt3() {
	Sleep(2000);
	std::cout << "子线程3\n";
}

现在我们想让他们四个同时执行?如何操作。

  1. 首先来创建线程对象:

thread 用作线程对象类型,然后传递一个函数指针(以模板形式)给到这个对象,则这个对象就是一个线程对象

我们将这三个子线程分别为三个不同的线程对象。print1为主线程。

std::thread t1(printtttt1);
std::thread t2(printtttt2);
std::thread t3(printtttt3);

创建完成后我们使用 join将子线程添加到主线程中:

t1.join(); 
t2.join();
t3.join();

然后运行,就会发现,三个子线程和主线程同时结束,说明多线程有效。

int main() {
	std::thread t1(printtttt1);
	std::thread t2(printtttt2);
	std::thread t3(printtttt3);
	//t.join(); //子线程加入主线程
	//detach: 子线程和主线程各自玩个的,等待主线程执行完毕
	t1.join(); 
	t2.join();
	t3.join();
	print1();
	return 0;
}

观察到细节:

  • 三个子线程都有一个等待两秒的功能,如果不是多线程,则很容易想到单纯的运行这四个函数可能需要6秒多才完成
  • 但是他们四个是同时完成的,即只用了两秒
  • 并且我们没有限制线程之间的执行顺序,因此他们的顺序是任意的。

在这里插入图片描述


join函数就是将子线程加入到主线程,然后和主线程一起执行完毕。

还有个 detach函数:

  • detach: 子线程和主线程各玩各的的,等待主线程执行完毕则停止。
t1.detach();
t2.detach();
t3.detach();
print1();

则会出现什么?

  • 程序立刻结束,我管你子线程执行了没有,只要我的主线程结束了,则程序就结束。 因此程序直接执行主线程函数,而不会执行三个子线程。

在这里插入图片描述


joinable:对线程是否可以join和detach操作进行判断。即一个线程只能进行一次join或者detach操作,如果你写了很多的代码,明明已经join过一次了,但是忘记了,因此又join了一次,这时就会 报错!!!

该函数在可以 join 或 detach 的时候返回true,否则返回false。

因此常见的可以避免错误的方式:

if (t1.joinable()) {
		t1.join(); //t1.detach()
	}

创建线程的多种方式

thread类型的构造函数是怎样的呢? 它可以构造什么样的线程函数对象呢?

template <class _Fn, class... _Args,   .......... >
explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
        _Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
}
  • Fn:接受一个函数指针。
  • Args:接受函数的参数。

无参函数

这是最简单的创建线程的方式:

// 1. 传递无参void函数
void print() {
	std::cout << "子线程: " << "传递无参void函数\n";
}
void create1() {
	std::thread t1(print);
	t1.join(); //加入主线程
}

lambda表达式

// 2. 传递lambda表达式
void create2() {
	std::thread t1([]() {
		std::cout << "lambda表达式\n";
		});

	if (t1.joinable()) {
		t1.join();
	}
}

常成员函数

  • 普通内置类型:int
  • 常引用:const string& ; const int&
  • 常指针:const int*
  • 都可以直接传递
// 3. 传递有参函数
// 3.1  普通参数
void print2(int num, const std::string& name, const int age, const int& yina, const int* cp) {
	std::cout << "num: " << num << " name: " << name << " age: " << age << " yina: "
		<< yina << " cp: " << *cp << '\n';
}
void create3() {
	int num = 10, age = 20, yina = 999, cpnum = 50;
	std::thread t1(print2, num, "你好", age, yina, &cpnum);
	if (t1.joinable()) {
		t1.join();
	}
}

not常成员引用函数

  • not常引用: 如果是**不带const**的引用类型,则必须使用 std::ref 修饰,否则会报错:
  • not常指针:不会报错。
// 必须加以 ref 修饰;否则就传递const的引用
void print3(int& num) {
	std::cout << "引用 num: " << num << '\n';
}
void create4() {
	int num = 10;
	std::thread t1(print3, std::ref(num));
	if (t1.joinable()) {
		t1.join();
	}
}

//不会报错,const和非const的指针都不会报错,传递地址即可
void print4(int* num) {
	std::cout << "指针 num: " << *num << '\n';
}
void create5() {
	int num = 10;
	std::thread t1(print4, &num);
	if (t1.joinable()) {
		t1.join();
	}
}

智能指针

传递智能指针 unique_ptr 需要加 move移动,因为unique_ptr只允许存在一份,但是移动后本地将消失。

void print5(std::unique_ptr<int> ptr) {
	std::cout << "智能指针: " << *ptr.get() << '\n';
}
void create6() {
	std::unique_ptr<int> pointer(new int{ 100 });
	std::thread t1(print5, std::move(pointer));
	if (t1.joinable()) {
		t1.join();
	}

	//null
	std::cout << "移动之后,智能指针: " << pointer.get() << '\n';
}

仿函数

直接传递即可。

class Foo {
public:
	Foo() {}
	void operator()() {
		std::cout << "仿函数\n";
	}
};
void create7() {
	Foo f = Foo();
	//1. 仿函数对象
	std::thread t1(f);
	if (t1.joinable()) {
		t1.join();
	}

	//2. 匿名函数对象
	std::thread t2((Foo()));
	if (t2.joinable()) {
		t2.join();
	}
}

类的普通成员函数

函数指针的形式,先传递类名所对应的**函数地址,然后再传递类对象**。

class Aoo {
public:
	Aoo() {}
	void test() {
		std::cout << "普通成员函数\n";
	}
};
void create8() {
	Aoo a = Aoo();
	std::thread t1(&Aoo::test,a);
	if (t1.joinable()) {
		t1.join();
	}
}

综合测试

int main() {
	create1();
	create2();
	create3();
	create4();
	create5();
	create6();
	create7();
	create8();
	return 0;
}

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/164414.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Qt实现多人聊天工作室

目录 1、项目背景 2、技术分析 3、架构设计 3、1 服务器架构 3.1.1 模块划分 3.1.2 模块之间的交互 3、2 客户端架构 3.2.1 模块划分 3.2.2 模块之间交互 4、实现过程 4、1 功能实现 4.1.1 用户登录注册功能​编辑 4.1.2 用户主界面功能 4、2 设计实现 4.2.1 登录…

传输层协议-TCP协议

目录 TCP协议格式理解可靠性序号与确认序号16位窗口大小六个标志位连接管理机制三次握手四次挥手 确认应答机制&#xff08;ACK&#xff09;超时空重传机制流量控制滑动窗口拥塞控制延迟应答捎带应答面向字节流粘包问题TCP异常情况TCP小结基于TCP应用层协议TCP/UDP对比用UDP实现…

程序的编译链接以及装载

目录 一、预处理 二、编译 三、汇编 四、链接 五、装载 一、预处理 读取c源程序&#xff0c;对其中的伪指令&#xff08;以#开头的指令&#xff09;和特殊符号进行处理&#xff0c; 伪指令主要包括以下五个方面&#xff1a; 宏定义指令&#xff0c;如#define Name Token…

如何定位el-tree中的树节点当父元素滚动时如何定位子元素

使用到的方法 Element 接口的 scrollIntoView() 方法会滚动元素的父容器&#xff0c;使被调用 scrollIntoView() 的元素对用户可见。 参数 alignToTop可选 一个布尔值&#xff1a; 如果为 true&#xff0c;元素的顶端将和其所在滚动区的可视区域的顶端对齐。相应的 scrollIntoV…

基于冠状病毒群体免疫算法优化概率神经网络PNN的分类预测 - 附代码

基于冠状病毒群体免疫算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于冠状病毒群体免疫算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于冠状病毒群体免疫优化的PNN网络5.测试结果6.参考文献7.Matlab代码 …

再高级的打工人也只是打工人!

再高级的打工人也只是打工人&#xff01; OpenAI CEO 奥特曼被罢免的事情人尽皆知「虽然&#xff0c;今天又复职了。。」&#xff0c;我们能从中学到什么呢&#xff1f; CEO 也能被裁&#xff0c;这应该是最近几年被裁名单里面&#xff0c;职级最高的一个人了吧。你再也不用担…

2023最新最全【Nacos】零基础安装教程

一、下载Nacos1.4.1 二、单机版本安装 2.1 将下载的nacos安装包传输到服务器2.2 解压文件2.3 进入bin目录下 单机版本启动2.4 关闭nacos2.5 访问Nacos地址 IP&#xff1a;8848/nacos 三、集群版本的安装 3.1 复制nacos安装包&#xff0c;修改为nacos8849&#xff0c;nacos88…

cesium 图片旋转

cesium 图片旋转 1、实现思路 用cesium 中 ellipse 方法来加载圆型&#xff0c;改变 material 材质 用 ImageMaterialProperty 属性来加在图片&#xff0c;实时改变rotation&#xff0c;stRotation属性来实现旋转 2、源码实现 <!DOCTYPE html> <html lang"en&…

自定义业务异常处理类加入全局处理器中

自定义业务异常处理类并将其加入全局异常处理器&#xff0c;从而避免业务层直接处理异常造成代码污染&#xff0c;达到业务清晰简洁。 描述 在进行分类模块开发时&#xff0c;删除某个分类时当分类关联了菜品和套餐时&#xff0c;是不允许删除的。我们在管理端删除的时候会提示…

lectin

PSGL-1 ; selectin O-linked glycosylation | Detailed Pedia PSGL-1 has several O-glycans to extend the ligand away from the cell surface. An sLex epitope allows interactions with the receptor for leukocyte localisation. 分类 --Recognition by Animal Lectins…

【linux网络】解读FTP文件传输服务器配置,揭秘百度云下载限速原理

目录 一、FTP文件传输协议 1.1FTP工作原理 1.2两种模式介绍 1.3FTP状态码 1.4FTP的三种用户分类 二、vsftpd软件的介绍 2.1服务端介绍 2.2不同操作系统下的客户端登录操作 三、vsftpd的常见配置 3.1修改默认的命令端口 3.2限制匿名用户登录&#xff08;系统原本是默…

实验五:Java多线程程序设计

一、线程接力 编写一个应用程序&#xff0c;除了主线程外&#xff0c;还有三个线程&#xff1a;first、second和third。first负责模拟一个红色的按钮从坐标&#xff08;10&#xff0c;60&#xff09;运动到&#xff08;100&#xff0c;60&#xff09;&#xff1b;second负责模…

安顿APP3.0全新升级,引领智能穿戴健康革新,专注预警疾病风险

随着人们生活水平的提高和工作压力的增加&#xff0c;心脑血管疾病已经成为现代社会的严重问题&#xff0c;特别是心梗、脑卒中等疾病已经开始夺去年轻人的生命。 据报道&#xff0c;近年来&#xff0c;多位年轻人因心脑血管疾病突发去世&#xff0c;如42岁的知名男演员、30岁的…

【STL】:反向迭代器

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关反向迭代器的模拟实现&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通…

Web之JavaScript(jQuery)笔记

Web之HTML、CSS、JavaScript 三、JavaScriptJS调试变量自定义函数数据类型及转换运算符优先级内置函数数组事件DOM(Document Object Model 文档对象模型)jQuery Web之HTML笔记 Web之CSS笔记 三、JavaScript JavaScript&#xff08;简称“JS”&#xff09;是一种轻量级的面向对…

计算机组成原理-双端口RAM和多模块存储器

文章目录 存取周期总览双端口RAM多体并行存储器低地址交叉编址有多少个存储体合适&#xff08;体号&#xff09;多模块存储器&#xff08;多体存储器&#xff09;总结实际场景 存取周期 总览 双端口RAM RAM&#xff1a;用于主存或高速缓存&#xff0c;断电数据丢失 多体并行…

AI对开发者职业的影响,保持领先的7 个行动指南

在不断发展的技术领域&#xff0c;人工智能(AI)已经成为一股变革性的力量&#xff0c;重塑了行业&#xff0c;重新定义了我们解决问题的方式。对于开发人员来说&#xff0c;学习AI的决定不仅仅是为了保持相关性&#xff0c;而是在他们的职业生涯中开启一个新的可能性维度。 1.…

HR应用在线人才测评,给企业招聘带来的好处

一、什么是人才测评&#xff1f; 人才测评是指运用一系列的科学方法&#xff0c;对人的基本素质&#xff0c;专业能力&#xff0c;心理健康&#xff0c;性格进行选拔&#xff0c;评价及发展人才的一种科学方法。近十多年&#xff0c;它被广泛运用于国有大型企业的人才招聘和人…

【力扣面试经典150题】(链表)K 个一组翻转链表

题目描述 力扣原文链接 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只…

C++多线程编程(3):接收线程处理函数的返回值

文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 文章目录 处理带返回值的函数asyncpackaged_taskpromise 处理带返回值的函数 有三种方法&#xff1a; asyncpackaged_taskpromise async 第一种方法是使用 async 函数。 步骤&#xff1a; 使用 async 创建线程处理函…