C++ 多线程 学习笔记

2023-11-05

线程睡眠很稳定,但无线程睡眠不稳定


线程调用类方法:


有参数时调用方法:


当参数为引用时:


detach分离线程,分离线程与主线程同时进行,join会使主线程挂起,执行join进来的进程

detach必须让主线程在还住运行的情况下调用,换句话说就是不能让detach的线程还没结束,主线程就结束,同时detach的函数传参不能是局部变量,换句话来说就是不能调用的函数还没结束,该变量就被销毁了


当同一资源被多个线程同时引用时,为防止资源抢占,使用mutex,互斥锁

头文件#include "mutex"


lock_guard<类型> 变量名(锁变量);

作用,为防止死锁发生,它可以进行锁的自动加锁和解锁


unique_lock<类型> 变量名(锁名, 变参参数);

延时加锁,直接这样定义数据会出现混乱

必须手动锁定 

直接用变参std::adopt_lock也会直接造成数据混乱 

std::adopt_lock只是用于接管之前的锁mtx,所以在这一行之前需要对mtx进行lock才会真正的被lock


#include <condition_variable>

用于主线程,子线程按次序执行

如果需要线程一个一个执行,则可以这样写

#include "iostream"
#include "chrono"
#include "thread"
#include "condition_variable"
#include "mutex"

using namespace std;

mutex mtx;
condition_variable cv;
bool sub_run = false;
int number = 0;

class A {
public:
	void add(int &b) {
		while (b < 10) {
			unique_lock<mutex> queLock(mtx);
			cv.wait(queLock, [&] { return !(number - 1); });
			b++; 
			cout << " add " << b << endl;
			this_thread::sleep_for(chrono::milliseconds(10));
			number = 2;
			cv.notify_all();
		}
	}
};

void Dec(int& c) {
	while (c < 10) {
		unique_lock<mutex> uniLock(mtx);
		cv.wait(uniLock, [&] { return !number; });
		c--;
		cout << " Dec " << c << endl;
		this_thread::sleep_for(chrono::milliseconds(10));
		number = 1;
		cv.notify_all();
	}
}

int main() {
	A a;
	int num = 5;
	thread th(&A::add, &a, ref(num));
	thread th1(Dec, ref(num));
	while (num < 10) {
		unique_lock<mutex> mainUniLock(mtx);
		cv.wait(mainUniLock, [&] { return !(number - 2); });
		num++;
		cout << " Main " << num << endl;
		this_thread::sleep_for(chrono::milliseconds(10));
		number = 0;
		cv.notify_all();
	}
	th.join();
	th1.join();
	cout << num << endl;

	return 0;
}


nofity_one()只会随机唤醒其中运行的一个线程


call_once(once_flag, this_thread::get_id());

头文件:  #include "mutex"

作用:线程只能调用该方法一次

只调用了一次

主线程没有限制 


如何在join前就获取最终num的结果?

promise     future

头文件:#include "future"


自定义启动线程函数:

头文件#include "future"

packaged_task<函数类型> 变量名(函数名);

主要是能与promise、future搭配使用


async

头文件#include "future"

fvalue.get()过后才会进行函数调用


原子操作

允许无所并发编程,涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的,原子对象不具有数据竞争

头文件:#include "atomic"

锁是在牺牲性能的情况下进行对操作的细致管控,这个时候就用原子变量

不加锁:

加锁:

原子操作:


C++11 多线程std:: async与std::thread的区别_c++11 thread asy-CSDN博客

参考:60 工具库-tuple_哔哩哔哩_bilibili


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	int a = 1;
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	th.join();
	
}

// Called every frame
void ATaskTest::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		//std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
		mtx.unlock();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	th.detach();
}

// Called every frame
void ATaskTest::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
		mtx.unlock();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	std::thread th1(&ATaskTest::ThreadDo1, this, std::ref(a));
	th.detach();
	th1.detach();
}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

会一增一减


// Fill out your copyright notice in the Description page of Project Settings.


#include "TaskTest.h"
#include "chrono"
#include "Kismet/KismetSystemLibrary.h"
#include "mutex"
#include "thread"

// Sets default values
ATaskTest::ATaskTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void ATaskTest::BeginPlay()
{
	Super::BeginPlay();
	std::thread th(&ATaskTest::ThreadDo, this, std::ref(a));
	std::thread th1(&ATaskTest::ThreadDo1, this, std::ref(a));
	th.detach();
	th1.detach();
}

std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		std::unique_lock<std::mutex> uniLock(mtx, std::defer_lock);
		uniLock.lock();
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

unique_lock与lock_guard一样,在函数结束后会自动解锁,但unique_lock有更多操作,比如延迟加锁,接管锁,wait锁(wait不接受lock_guard)如果不需要这些操作还是lock_guard好一点,越多操作性能消耗也越高


std::mutex mtx;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		std::unique_lock<std::mutex> uniLock(mtx, std::adopt_lock);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::lock_guard<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}


std::mutex mtx;
std::condition_variable cv;
bool isFirst = false;
void ATaskTest::ThreadDo(int& value) {
	while (value < 10000) {
		mtx.lock();
		std::unique_lock<std::mutex> uniLock(mtx, std::adopt_lock);
		cv.wait(uniLock, [=] {return !isFirst; });
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value++;
		isFirst = true;
		cv.notify_all();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

void ATaskTest::ThreadDo1(int& value) {
	while (value < 10000) {
		std::unique_lock<std::mutex> guardLock(mtx);
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
		cv.wait(guardLock, [=] {return isFirst; });
		UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
		value--;
		isFirst = false;
		cv.notify_all();
	}
	UKismetSystemLibrary::PrintString(this, FString::FromInt(value));
}

while内一个执行一次,使用std::condition_variable


std::atomic_int a(1);
void ATaskTest::ThreadDo() {
    while (a < 10000) {
        a++;
        //UKismetSystemLibrary::PrintString(this, FString::FromInt(a));
    }
}

void ATaskTest::ThreadDo1() {
    while (a < 10000) {
        a--;
        //UKismetSystemLibrary::PrintString(this, FString::FromInt(a));
    }
}

atomic_int暂时没找到打印的办法,但是能够编过断点也有对应效果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 多线程 学习笔记 的相关文章

  • HTML表格(table)实例

    实例1 课程表 table border 1 width 60 cellpadding 2 caption 课程表 caption tr align center td 时间 日期 td td 一 td tr table
  • 附近的商店

    看着每天的感染数据在下降 上海解封的日子快到了 打开美团看看附近店铺有没有好吃 准备解封大吃特吃一顿 排序按照距离优先 还有附近几公里之内的店铺 想了解这个功能怎么实现的 查了网上资料 得到的常用的算法是 geohash 和 S2 Geoh
  • Reverse题常规步骤

    Reverse题常规步骤 1 查壳 一般难度的题目都是加了壳的 都需要进行壳分析 2 脱壳 有壳就脱壳 3 IDA逆向 脱完壳以后用IDA进行逆向分析

随机推荐

  • CentOS7.x环境下安装Docker以及常用命令

    Docker官方建议在Ubuntu中安装 因为Docker是基于Ubuntu发布的 而且一般Docker出现的问题Ubuntu是最先更新或者打补丁的 在很多版本的CentOS中是不支持更新最新的一些补丁包的 我这里将Docker安装到阿里云
  • 人脸识别损失函数综述(附开源地址)

    原文 人脸识别损失函数综述 附开源地址 原文地址 https zhuanlan zhihu com p 51324547 常用的度量学习损失方法有对比损失 Contrastive loss 三元组损失 Triplet loss 四元组损失
  • Android 蓝牙串口通信Demo

    目录 一 前言 二 效果图 三 源码 带注释 1 布局代码 2 Java代码 3 权限声明 四 注意 五 项目源码下载 一 前言 在学校和机电的同学组队准备做一个智能小车去参加比赛 需要我开发一个小车的控制app 所以我开始学习蓝牙串口通信
  • 一文带你深入了解HTTP

    http的发展史 在学习网络之前 了解它的历史能够帮助我明白为何它会发展为如今这个样子 能让我有探究它的兴趣 下面的这张图片就展示了 互联网 诞生至今的发展历程 http是什么 HyperTextTransferProtocol 直译为 超
  • sql代码转换小工具(delphi)

    1 下载 2 粘贴sql语句 3 msql转换为delphi sql语句
  • shell脚本基础3——正则表达式

    文章目录 一 基本了解 二 基本正则表达式 2 1 字符匹配 2 2 位置锚定 2 3 匹配次数 2 4 分组 三 扩展正则表达式 3 1 字符匹配 3 2 位置锚定 3 3 匹配次数 3 4 分组 3 5 或者 一 基本了解 正则表达式分
  • 对表的简单查询

    SQL命令对表进行查询 目录 SQL命令对表进行查询 1 无条件查询 2 条件查询 3 统计汇总查询 4 分组查询 5 对查询结果排序 1 无条件查询 无条件查询指只包含 SELECT FROM 的查询 这种查询最简单 例如 在S表中查询所
  • Android Studio安装中的问题及第一次运行hello world程序

    总结一下 在安装Android Studio中可能出现和遇到的问题 并给出解决方案 1 AS在安卓官网可以直接下载完整的安装包 2 SDK找不到的情况 可以自己下载 参考 https www jianshu com p 4ac1313b50
  • 自定义动态数据源

    文章目录 准备 业务流程分析 代码实现 网页上切换数据源 准备 mysql spring boot 配置依赖 配置文件 数据源配置 spring datasource type com alibaba druid pool DruidDat
  • UnityVR--小程序3--金色的子弹2

    子弹需要一个打击目标 目标具备一定的生命值 HP 当生命值将为0时 目标被击落并消失 1 前篇的AXButton cs脚本不需要修改 2 子弹的程序Bullet cs中 OnTriggerEnter Collider other 函数修改为
  • 肖战

    肖战是中国内地男演员 歌手 主持人 毕业于中央戏剧学院表演系 他曾出演过多部影视剧 包括 花千骨 武媚娘传奇 和 长安十二时辰 此外 他还是一位多才多艺的歌手 曾发行过多张个人音乐专辑
  • 苹果开发平台常用网址链接

    苹果开发者中心 https developer apple com cn 苹果开发者中心 企业类型 https developer apple com cn programs enterprise 注册账号 https developer
  • react+antd实现Table拖拽调整列宽

    注意 列需要传入 width 并且配合下面的css样式才能显示拖拽手势 import React useEffect useState from react import Table from antd import Resizable f
  • PE半透明屏是怎么制造的?工艺、材料、应用

    PE半透明屏是一种新型的屏幕材料 具有半透明的特点 它由聚乙烯 PE 材料制成 具有良好的透明度和柔韧性 PE半透明屏广泛应用于建筑 广告 展览等领域 具有很高的市场潜力 PE半透明屏的特点之一是其半透明性 它可以在一定程度上透过光线 使得
  • 相关性分析热力图(Python&Matlab代码实现)

    目录 1 热力图 1 1 简介 1 2 语法 2 算例1 Python代码实现 2 1 算例 2 2 Python代码 2 3 运行结果 3 算例2 Python代码实现 4 算例3 Python代码实现 4 1 算例 4 2 Python
  • 小电容通高频大电容通低频的理解

    本文参考为什么电容通高频阻低频 记录下个人理解并总结 1 电容的作用是通高频阻低频 高频的时候电容总是还没充满电 负半周期便到来 所以电流始终存在 低频的时候信号交流电负半周还没到来 电容已充满电便发生断路 2 理论上电容越大 能通越高的高
  • 简单解释同步、异步、阻塞、非阻塞、中断、轮询、多线程,协程这几个概念(代码未验证,仅参考)

    科普 同步和异步的区别 同步和异步是指程序执行的方式 其中同步指程序按顺序执行 每个任务必须等待前面的任务执行完成后才能执行 而异步则指程序可以在执行一个任务时同时执行另一个任务 不需要等待前一个任务执行完毕 同步 Synchronous
  • supervisor源码分析

    Supervisor分析 1 运行原理概述 Supervisor生成主进程并将主进程变成守护进程 supervisor依次生成配置文件中的工作进程 然后依次监控工作进程的工作状态 并且主进程负责与supervisorctl客户端通信 实现主
  • c语言中求三个整数中的最大值和最小值,编程用指针实现输入三个整数,求其中的最大值...

    公告 为响应国家净网行动 部分内容已经删除 感谢读者理解 话题 编程用指针实现输入三个整数 求其中的最大值回答 include stdio h int getmax int p int n int i max p max p p 0 for
  • C++ 多线程 学习笔记

    线程睡眠很稳定 但无线程睡眠不稳定 线程调用类方法 有参数时调用方法 当参数为引用时 detach分离线程 分离线程与主线程同时进行 join会使主线程挂起 执行join进来的进程 detach必须让主线程在还住运行的情况下调用 换句话说就