C++多线程编程(第一章 多线程基本使用)

news2024/10/6 20:25:54

C++ 11;
C++ 14;
C++ 17;
C++ 20;

1、为什么要多线程

任务分解

耗时的操作,任务分解,实时响应

数据分解

充分利用多核CPU处理数据

数据流分解

读写分离,解耦合设计

2、相关代码

1、初步: join(),detach()

#include <thread>
#include <iostream>
// Linux -lpthread  //linux系统

using namespace std;
bool is_exit = false;//子线程是否退出

void ThreadMain()
{

	cout << "begin sub thread main" << this_thread::get_id() << endl;
	for (int i = 0; i < 10; i++)
	{//等待10秒
		if (is_exit)
		{
			break;
		}
		printf("thread:%d\n",i);
		//this_thread::sleep_for(10ms);//1000ms
		this_thread::sleep_for(chrono::seconds(1));// 两种方法都可以
	}
	cout << "end sub thread main" << this_thread::get_id() << endl;

}

int main()
{
	cout << "main thread ID" << this_thread::get_id() << endl;//获取线程ID
	{
		thread th(ThreadMain);
		this_thread::sleep_for(chrono::seconds(5));// 两种方法都可以
		is_exit = true;
		cout << "主线程阻塞,等待子线程退出" << endl;
		th.join();//阻塞
		cout << "子线程退出" << endl;
	}
	
	//{
	//	thread th(ThreadMain);
	//	th.detach();//子线程与主线程分离,守护线程;这里需要注意坑
	//	//坑:主线程退出后,子线程不一定退出,如果这时候子线程访问退出的主线程变量,则会异常
	//}
	
	getchar();

	return 0;
}

2、实体传参代码:

#include <thread>
#include <iostream>
// Linux -lpthread  //linux系统

using namespace std;

class Para
{
public:
	Para() { cout << "Crate Para" << endl; }
	Para(const Para& p) {//重定义拷贝构造函数,覆盖原始的拷贝构造函数
		cout << "Copy Para" << endl;
	this->name = p.name;
	}
	~Para() { cout << "Drop Para" << endl; }


	string name;
};

void ThreadMain(int p1,float p2,string str, Para p4)
{
	this_thread::sleep_for(100ms);
	cout << "Thread main:" <<p1<<" "<<p2<<" "<< str.c_str()<<" "<<p4.name.c_str()<< endl;

}

int main()
{
	cout << "main thread ID" << this_thread::get_id() << endl;//获取线程ID
	thread th;
	{
		float f1 = 12.1f;
		Para p;
		p.name = "Test para class";
		//所有参数做复制
		th = thread(ThreadMain, 101, f1, "test string param",p);
	}
	th.join();

	getchar();

	return 0;
}

实体传参,创建一次,复制了两次,销毁了3次
在这里插入图片描述

3、指针、引用传参

#include <thread>
#include <iostream>
// Linux -lpthread  //linux系统

using namespace std;

class Para
{
public:
	Para() { cout << "Crate Para" << endl; }
	Para(const Para& p) {//重定义拷贝构造函数,覆盖原始的拷贝构造函数
		cout << "Copy Para" << endl;
	this->name = p.name;
	}
	~Para() { cout << "Drop Para" << endl; }


	string name;
};

void ThreadMain(int p1,float p2,string str, Para p4)
{//普通传参
	this_thread::sleep_for(100ms);
	cout << "Thread main:" <<p1<<" "<<p2<<" "<< str.c_str()<<" "<<p4.name.c_str()<< endl;
}

void ThreadMainPtr(Para*p)
{//传递指针
	this_thread::sleep_for(100ms);
	cout << "ThreadMain Prt name=" << p->name.c_str() << endl;
}

void ThreadMainRef(Para&p)
{//传递引用
	this_thread::sleep_for(100ms);
	cout << "ThreadMain Ref name=" << p.name.c_str() << endl;
}


int main()
{
	cout << "main thread ID" << this_thread::get_id() << endl;//获取线程ID

	//正常情况
	{
		Para p;//调用初始化
		p.name = "Test para class";
		thread th(ThreadMainPtr,&p);
		th.join();

	}//调用销毁
	printf("Demo2:\n");

	{//异常情况演示,主程序结束了,参数p也销毁了,所以子线程中访问不到
		Para p;
		p.name = "Test para detach";
		thread th(ThreadMainPtr, &p);
		th.detach();//主线程与子线程分离,守护线程

	}
	getchar();
	printf("Demo3:\n");
	{//传递引用

		Para p;
		p.name = "Test para ref";
		thread th(ThreadMainRef, ref(p));//传递引用需要在外面增加ref()标记引用类型,否则编译会报错
		th.join();

	}
	getchar();
	return 0;
}

指针、引用传参,创建一次,复制了两次,销毁了3次
在这里插入图片描述

4、成员函数作为子线程传入

//演示成员函数进行传参
#include <thread>
#include<iostream>
#include <string>
using namespace std;

class MyThread
{
public:
	//入口线程函数
	void Main()
	{
		cout << "MyThread Main:" << name.c_str() << " : "<< age << endl;
	}

	string name="";
	int age = 100;
};


class XThread
{
public:
	virtual void Start() //虚函数,可以在子函数中重载它
	{
		is_exit_ = false;//不退出
		th_ = std::thread(&XThread::Main,this);//创建线程
	}


	virtual void Wait()
	{
		if (th_.joinable())
		{
			th_.join();
		}
	}

	virtual void Stop()
	{
		is_exit_ = true;//退出
		Wait();
	}

	bool is_exit() { return is_exit_; }//谷歌的编码标准
private:
	virtual void Main() = 0;//定义纯虚函数,纯虚函数在子函数中必须实现,否则报错
	std::thread th_;
	bool is_exit_ = false;//是否退出线程循环

};


class TestXThread :public XThread//继承
{
public:
	void Main() override//增加 override 检查重写父类的函数
	{
		cout << "Begin:TestThread Main ,name:"<<name << endl;
		
		while (!is_exit())
		{
			this_thread::sleep_for(100ms);
			cout << "." << flush;

		}
		cout << "TestThread Main end!" << endl;
	}
	string name;
};

int main()
{
	{
		MyThread myth;
		myth.name = "Test name 001";
		myth.age = 20;
		thread th(&MyThread::Main, &myth);//以成员函数方式
		th.join();
	}
	printf("Demo2:\n");
	TestXThread testth;
	testth.name = "TestXThread name";
	testth.Start();
	//getchar();
	this_thread::sleep_for(3s);


	testth.Stop();//
	//testth.Wait();//


	getchar();
	return 0;
}

在这里插入图片描述

5、Lambda匿名(临时)函数多线程

#include <thread>
#include <iostream>
#include <string>

using namespace std;

class TestLambda
{
public:
	void Start()
	{
		thread th([this]() {cout << "name=" << name << endl; });//成员的匿名线程函数
		th.join();

	}
	string name = "test lambda in Class";
};

int main()
{
	thread th([](int i) {cout << "test lambda" << i << endl; }, 123);
	th.join();

	TestLambda test;
	test.Start();


	return 0;

}

在这里插入图片描述

6、call_once多线程调用函数,但是函数只进入一次


#include <thread>
#include <iostream>
#include <string>
#include <mutex>


using namespace std;

void SystemInit()
{
	cout << "Call SystemInit" << endl;
}

void SystemInitOne()
{//C++ 11
	static std::once_flag flag;
	std::call_once(flag,SystemInit);

}

int main()
{
	printf("普通调用测试:\n");
	SystemInit();
	SystemInit();

	for (int i = 0; i < 3; i++)
	{
		thread th(SystemInit);
		th.detach();
	}
	getchar();

	printf("下面为只调用一次测试:\n");

	SystemInitOne();
	SystemInitOne();
	for (int i = 0; i < 3; i++)
	{
		thread th(SystemInitOne);
		th.detach();
	}
	getchar();

	return 0;
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数学建模】时间序列分析

文章目录 1. 条件2. 模型分类3. SPSS处理时间序列 1. 条件 1.使用于具有时间、数值两种要素 2.数据具有周期性可以使用时间序列分解 2. 模型分类 叠加模型【YTSCI】 序列的季节波动变化越来越大&#xff0c;反映变动之间的关系发生变化乘积序列【YTSC*I】 时间序列波动保持恒…

JavaSwing+MySQL的学生选课系统

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88101629?spm1001.2014.3001.5503 Jdk&#xff1a;1.8 MySQL&#xff1a;5.7 功能&#xff1a;可以进行选课与查看学生基本资料 在这里插入图片描述

Jmeter GET 请求 参数为 Json 串且参数中存在变量的转化

目录 前言&#xff1a; 1.在 HTTP 请求下添加 BeanShell PreProcessor 前置处理器&#xff1a; 2.在 BeanShell PreProcessor 的实现&#xff1a; 3.在 HTTP 请求中的使用方式&#xff1a; 4.参数化的数据方式&#xff1a; 5.请求结果&#xff1a; 前言&#xff1a; 在 A…

网络流量监视器vnStat

什么是 vnStat &#xff1f; vnStat 是一个网络流量监视器&#xff0c;它使用内核提供的网络接口统计信息作为信息源。这意味着 vnStat 实际上不会嗅探任何流量&#xff0c;并且无论网络流量速率如何&#xff0c;都可以确保系统资源的轻度使用。 安装 在群晖上以 Docker 方式安…

Hive内部表和外部表

表类型详解 表分类 在Hive中,表类型主要分为两种 第一种&#xff1a;内部表 也叫管理表表目录会创建在集群上的{hive.metastore.warehouse.dir}下的相应的库对应的目录中。默认创建的表就是内部表 第二种&#xff1a;外部表 外部表需要使用关键字"external"&#xff…

勘探开发人工智能应用:地震层位解释

1 地震层位解释 层位解释是地震构造解释的重要内容&#xff0c;是根据目标层位的地震反射特征如振幅、相位、形态、连续性、特征组合等信息在地震数据体上进行追踪解释获得地震层位数据的方法。 1.1 地震信号、层位与断层 图1.1 所示为地震信号采集的过程&#xff0c;地面炮…

Sip网络音频对讲广播模块, sip网络寻呼话筒音频模块

Sip网络音频对讲广播模块&#xff0c; sip网络寻呼话筒音频模块 一、模块介绍 SV-2101VP和 SV-2103VP网络音频对讲广播模块 是一款通用的独立SIP音频功能模块&#xff0c;可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议…

ks webdid 滑块注册

web和app其实都一样&#xff0c;主要是针对于设备进行风控&#xff0c;web设备叫webdid; webdid注册出来&#xff0c;过了ks滑块激活&#xff0c;测试了主页&#xff0c;评论等接口都可以跑&#xff0c;平均也就2s注册一个&#xff0c;如果开并发那就更快了&#xff1b; 不过一…

React Native 0.72 版本,带来诸多更新

经过漫长的等待,React Native 终于迎来了0.72 版本,此处版本带来了Metro重要的功能更新、性能优化、开发人员体验的改进以及其他一些重要的变化。我们可以从下面的链接中获取此次版本更新的内容:0.72更新内容 一、Metro 新功能 众所周知,Metro 是 React Native 默认的 Jav…

图像处理之hough圆形检测

hough检测原理 点击图像处理之Hough变换检测直线查看 下面直接描述检测圆形的方法 基于Hough变换的圆形检测方法 对于一个半径为 r r r&#xff0c;圆心为 &#xff08; a , b &#xff09; &#xff08;a,b&#xff09; &#xff08;a,b&#xff09;的圆&#xff0c;我们将…

模拟量采集S_ITR函数(信捷C语言FC)

模拟量采集和转换函数非常简单,这里不再介绍,想了解具体算法的可以查看下面博客文章: PLC模拟量输入 模拟量转换FC S_ITR_博途模拟量转换程序_RXXW_Dor的博客-CSDN博客模拟量采集、工业现场应用特别广泛、大部分传感器的测量值和输出信号都是线型关系,所以我们可以利用线性…

SpringBoot中定时任务开启多线程避免多任务堵塞

场景 SpringBoot中定时任务与异步定时任务的实现&#xff1a; SpringBoot中定时任务与异步定时任务的实现_霸道流氓气质的博客-CSDN博客 使用SpringBoot原生方式实现定时任务&#xff0c;已经开启多线程支持&#xff0c;以上是方式之一。 除此之外还可通过如下方式。 为什…

对话商汤王晓刚:“百模大战”下半场,如何才能突出重围?

点击关注 文 | 姚悦 今年最早发布的那批大模型&#xff0c;现在怎么样了&#xff1f; 近期&#xff0c;商汤科技宣布“商汤日日新SenseNova”大模型体系完成了第一次重大迭代。这距离其发布过去3个月时间。 “每天不断接到用户调用&#xff0c;收到建议反馈后&#xff0c;每隔…

Java开发基础系列(十二):集合对象(List接口)

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; Java开发基础系列(十二)&#xff1a;集合对象(List接口) ⏱️ 创作时间…

【技术】国标GB视频平台设备接入EasyCVR后,如何获取RTMP与RTSP视频流

安防视频监控平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&#xff0c;比…

esp32_arduino的开发库安装笔记

1.1 Arduino软件下载与安装 Arduino官网下载地址&#xff1a;https://www.arduino.cc/en/software。 1.2在线安装 选择文件 - 首选项。 在附加开发板管理器网址中添加以下链接中的一个。 (1)Stable release link: https://raw.githubusercontent.com/espressif/arduino-es…

2023第二届中国绿色钢铁国际大会 演讲嘉宾更新

2023第二届中国绿色钢铁国际峰会将于9月21日-22日在上海举办&#xff0c;本次会议线上线下同步举行。 峰会将从钢铁行业上中下游全产业链视角出发&#xff0c;聚焦能源及原料结构创新&#xff0c;传统高炉技术路线低碳化创新&#xff0c;氢能冶金、二氧化碳捕集、利用或储存技…

借降本增效之名,探索开闭原则架构设计

引语 在我们的研发生产活动中&#xff0c;经常会遇到如下类似的疑惑&#xff1a; 业务和技术在公司组织活动中&#xff0c;究竟应该各扮演什么样的角色&#xff1f; 技术的目的是什么&#xff1f; 研发生产活动中&#xff0c;如何提高生产事故发生的下限&#xff1f; 如何充…

el-table表格自动滚动

实现效果如下&#xff1a; 功能点&#xff1a; 1. 当表格内容超出时&#xff0c;自动滚动&#xff0c;滚动到最后一条之后在从头滚动。 2. 表格中的数据会定时刷新&#xff0c;刷新后数据更新。 3. 鼠标移入表格中&#xff0c;停止滚动&#xff1b;移出后&#xff0c;继续滚…

微信小程序数字键盘(仿微信转账键盘)

微信小程序input自带数字输入键盘&#xff0c;不过是直接调用的系统键盘&#xff0c;无法个性化。 代码中使用使用了Vant WeappVant UI小程序版&#xff0c;这里就不介绍相关安装说明了&#xff0c;大家自行安装Vant Weapp。 json 用到的组件 {"usingComponents": …