C++ 多线程(一)

C++ 多线程(一)

  • 1.std中的thread API 介绍
    • 开启一个线程
    • 获取线程信息API
    • 交换两个线程
  • 2.向线程里传递参数的方法
    • 第一种方式(在创建线程的构造函数后携带参数)
    • 第二种方式(Lambda)
    • 第三种方式(成员函数)
  • 3.互斥锁
  • 4.try_lock
  • 5.挂起和唤醒线程
  • 6.将主线程资源移动到其他线程
  • 7.lock_guard
  • 8.unique_lock
  • 9.call_once
  • 10.condition_variable


1.std中的thread API 介绍

开启一个线程

如下是定义一个线程

std::thread Thread1(ThreadFunc1)

其开始运行有两种方式,一个是阻塞当前调用进程,一个是异步的方式不会阻塞当前调用的进程

join会阻塞当前调用的进程

Thread1.join()

detach不会阻塞当前调用进程

Thread1.detach()

获取线程信息API

获取线程ID

Thread1.get_id()

判断线程是否是可启用的

Thread1.joinable() 

这样输出的值是true

	std::thread Thread1(ThreadFunc1);cout << Thread1.joinable() << endl;

如果传入的执行参数为空则是不可启用

	std::thread Thread1;cout << Thread1.joinable() << endl;

如果想获取计算机能创建的线程数

Thread1.hardware_concurrency()

获取当前线程ID

 std::this_thread::get_id()

使当前线程睡眠n秒
有两种方式,一种是std的,一种是windows底层的

	std::this_thread::sleep_for(chrono::seconds(2));

注意windows的睡眠需要引用头文件Windows.h

#include <Windows.h>
Sleep(1000);

交换两个线程

std::thread Thread1(ThreadFunc1)
std::thread Thread2(ThreadFunc2)
Thread1.spawn(Thread2)

2.向线程里传递参数的方法

先定义要在子线程执行的方法

void Func1(int a, const string& b)
{cout << a << endl;cout << b << endl;
}

第一种方式(在创建线程的构造函数后携带参数)

	std::thread NewThread1(Func1, 1, "Hello");NewThread1.join();

第二种方式(Lambda)

	int a = 100;std::thread NewThread2([&](int value1,const string& value2){cout << "=====================" << endl;cout << a << endl;cout << value1 << endl;cout << value2 << endl;},2,"World");NewThread2.join();

第三种方式(成员函数)

class FTestClass
{
public:void Run(int a,const string& b){cout << a << endl;cout << b << endl;}
};
	FTestClass TestClass;std::thread NewThread3(&FTestClass::Run, &TestClass, 3, "TestClass");NewThread3.join();

3.互斥锁

为了避免多线程之间的资源竞争自然需要这种互斥的锁

使用前需要引用头文件

#include <mutex>
mutex mx;
void NewThreadFunc()
{mx.lock();cout << "等待2s" << endl;std::this_thread::sleep_for(chrono::seconds(2));mx.unlock();
}
	for (size_t i = 0; i < 5; i++){std::thread th(NewThreadFunc5);th.detach();}

最后我们会发现每隔2s输出一次信息

我们每次使用锁都需要lock 和 unlock 这是十分不便利的,而且如果我们忘记解锁就会死锁
我们可以使用析构来实现这种自动解锁的方式

struct FEvent
{FEvent(){m.lock();}~FEvent(){m.unlock();}static mutex m;
};
mutex FEvent::m;

再使用宏包裹一下

#define LOCK_TEST FEvent LockEvent;

如下是在线程执行的函数,只需要定义一行就可以自动解锁

void NewThreadFunc()
{LOCK_TESTcout << "等待2s" << endl;std::this_thread::sleep_for(chrono::seconds(2));
}

4.try_lock

try_lock 返回bool 值,是否能上锁

static mutex mx;
void NewThreadFunc2()
{if (mx.try_lock()){cout << "等待2s" << endl;std::this_thread::sleep_for(chrono::seconds(2));mx.unlock();}else {cout << "锁被使用" << endl;}
}
	for (size_t i = 0; i < 5; i++){std::thread NewThread2(NewThreadFunc2);NewThread2.detach();}

最后输出我们会发现只打印了一个等待2s 和四个锁被使用

5.挂起和唤醒线程

定义在子线程执行的函数

void NewThreadFunc3()
{while (true){Sleep(1000);cout << "Hello" << endl;}
}

SuspendThread 用于挂起线程
ResumeThread 用于唤醒线程

	std::thread th(NewThreadFunc3);SuspendThread(th.native_handle());std::this_thread::sleep_for(chrono::seconds(2));ResumeThread(th.native_handle());

6.将主线程资源移动到其他线程

定义在子线程执行的函数

void NewThreadFunc4(const string& Value)
{cout << Value << endl;
}
	std::thread th1(NewThreadFunc4,move("Hello world"));std::thread th2 = move(th1);th2.detach();

将th1的所有权转移给th2。此时,th1不再代表任何线程(相当于th1处于“空”状态),而th2现在代表原来th1所代表的线程。这是因为std::thread是不可复制的,但可以移动。所以,这里通过移动赋值(或移动构造)将th1的线程所有权转移给th2。

7.lock_guard

类似我们之前自己封装的自动解锁的锁,不要手动调用unlock,函数执行完毕自动析构

mutex mx;
void NewThreadFunc5()
{lock_guard<mutex> lock(mx);cout << "Hello world" << endl;Sleep(2000);
}
	for (size_t i = 0; i < 5; i++){std::thread th(NewThreadFunc5);th.detach();}

每隔2s输出一次一共输出了5次

8.unique_lock

unique_lock 相对于上面的 lock_guard 多了更多的功能API 可以更自由丰富的操作锁

defer_lock 此参数是延时的意思,锁并不是立马生效,需要手动lock

unique_lock 也是过了作用域会自动解锁

static mutex mt;
void Func1()
{unique_lock<mutex> lock1(mt,defer_lock);// 不需要上锁的函数cout << "这是不需要上锁的函数" << endl;lock1.lock();cout << "这是需要上锁的函数" << endl;lock1.unlock();//lock2.try_lock_until(); 锁到某个时间点//lock2.release(); 释放//lock2.mutex();拿到锁本体//lock2.swap(); 交换//lock2.owns_lock(); 判断是否锁住
}

下面演示一个unique_lock 的 try_lock_for()方法

static timed_mutex timeMt;
void Func2()
{unique_lock<timed_mutex> lock2(timeMt, defer_lock);if (lock2.try_lock_for(chrono::seconds(2))){cout << "锁住2s后" << endl;this_thread::sleep_for(chrono::seconds(1));}else{cout << "锁正在被占用" << endl;}
}
	for (size_t i = 0; i < 5; i++){thread th(Func2);th.detach();}

我们会发现输出了2个锁住2s后和3个锁正在被占用,是因为这个锁定义了锁住的时间为2s,当第一次运行后只执行了1s第二次进入仍然没超过定义的锁的2s所以可以进入,而之后都超过2s了,故无法进入了。

9.call_once

顾名思义就是无论调用多少次只执行一次

once_flag oneFlag;
void Func3()
{call_once(oneFlag, [](){cout << "运行一次" << endl;});
}
	for (size_t i = 0; i < 5; i++){Func3();}

10.condition_variable

条件变量,一个地方可以等待直到通知这个等待就可以执行等待之后的代码

mutex tx1;
condition_variable cv;
void Func4()
{Sleep(1000);cv.notify_one();Sleep(1000);
}
	std::thread th(Func4);th.detach();unique_lock<mutex> Lock1(tx1);cv.wait(Lock1);cout << "运行Wait之后" << endl;

notify_one 是一个,还有多个版本notify_all

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

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

相关文章

自动驾驶训练-tub详解

在 Donkeycar 的环境里&#xff0c;“tub” 是一个很关键的术语&#xff0c;它代表的是存储训练数据的目录。这些数据主要来源于自动驾驶模型训练期间收集的图像和控制指令。 Tub 的构成 一个标准的 tub 目录包含以下两类文件&#xff1a; JSON 记录文件&#xff1a;其命名格式…

CVPR多模态破题密钥:跨模对齐,信息串供

关注gongzhonghao【CVPR顶会精选】当今数字化时代&#xff0c;多模态技术正迅速改变我们与信息互动的方式。多模态被定义为在特定语境中多种符号资源的共存与协同。这种技术通过整合不同模态的数据&#xff0c;如文本、图像、音频等&#xff0c;为用户提供更丰富、更自然的交互…

小米路由器3G R3G 刷入Breed和OpenWrt 插入可共享网络的usb随身WiFi

小米 R3G 参数&#xff08;以下加黑加粗需要特别关注&#xff0c;灰常详细&#xff09; 市面上有R3G和R3Gv2两种型号, 注意区分, 后者是缩水版, 没有USB口. 内存只有128M, Flash只有16M. 这里描述的只适用于R3G. 就是这样 操作步骤开始&#xff0c;&#xff0c;注&#xff1a…

SpringBoot实现Serverless:手撸一个本地函数计算引擎

前言 最近突然冒出一个想法&#xff1a;能不能用SpringBoot自己实现一个类似AWS Lambda或阿里云函数计算的执行引擎&#xff1f; 说干就干&#xff0c;于是从零开始设计了一套基于SpringBoot的Serverless执行框架。 这套框架支持函数动态加载、按需执行、资源隔离&#xff0c;甚…

Java排序算法之<插入排序>

目录 1、插入排序 2、流程介绍 3、java实现 4、性能介绍 前言 在 Java 中&#xff0c; 冒泡排序&#xff08;Bubble Sort&#xff09; 和 选择排序&#xff08;Selection Sort&#xff09; 之后&#xff0c;下一个性能更好的排序算法通常是 插入排序&#xff08;Insertion …

《计算机网络》实验报告七 HTTP协议分析与测量

目 录 1、实验目的 2、实验环境 3、实验内容 4、实验结果与分析 4.1 使用tcpdump命令抓包 4.2 HTTP字段分析 5、实验小结 5.1 问题与解决办法&#xff1a; 5.2 心得体会&#xff1a; 1、实验目的 1、了解HTTP协议及其报文结构 2、了解HTTP操作过程&#xff1a;TCP三次…

面试实战,问题十三,Redis在Java项目中的作用及使用场景详解,怎么回答

Redis在Java项目中的作用及使用场景详解&#xff08;面试要点&#xff09; 一、Redis的核心作用高性能缓存层 原理&#xff1a;Redis基于内存操作&#xff08;引用[2]&#xff09;&#xff0c;采用单线程模型避免线程切换开销&#xff0c;配合IO多路复用实现高吞吐&#xff08;…

Python - 100天从新手到大师 - Day6

引言 这里主要是依托于 jackfrued 仓库 Python-100-Days 进行学习&#xff0c;记录自己的学习过程和心得体会。 1 文件读写和异常处理 实际开发中常常会遇到对数据进行持久化的场景&#xff0c;所谓持久化是指将数据从无法长久保存数据的存储介质&#xff08;通常是内存&…

IP--MGER综合实验报告

一、实验目的完成网络设备&#xff08;路由器 R1-R5、PC1-PC4&#xff09;的 IP 地址规划与配置&#xff0c;确保接口通信基础正常。配置链路层协议及认证&#xff1a;R1 与 R5 采用 PPP 的 PAP 认证&#xff08;R5 为主认证方&#xff09;&#xff0c;R2 与 R5 采用 PPP 的 CH…

window的WSL怎么一键重置

之前用WSL来在windows和服务器之间传输数据&#xff0c;所以有很多数据缓存&#xff0c;但是现在找不到他们的路径&#xff0c;所以想直接重置 首先使用spacesniffer看一下C盘的情况&#xff1a;看起来&#xff0c;这个WSL真的占用了很多空间&#xff0c;但是我又不知道该怎么删…

卷积神经网络研讨

卷积操作原理: 特征向量与遍历:假设已知特征向量(如蓝天白云、绿油油草地特征),在输入图像的各个区域进行遍历,通过计算内积判断该区域是否有想要的特征。 内积计算特征:内积为 0 表示两个向量垂直,关系不好,无想要的特征;夹角越小,内积越大,代表区域中有想要的特征…

【EWARM】EWARM(IAR)的安装过程以及GD32的IAR工程模板搭建

一、简介 IAR官网 EWARM&#xff0c;即 IAR Embedded Workbench for ARM&#xff0c;是由 IAR Systems 开发的一款专门用于 ARM 微处理器软件开发的集成开发环境。以下是具体介绍&#xff1a; 功能特性&#xff1a; 完整工具链支持&#xff1a;集成了高级编辑器、全面的编译…

【工程化】浅谈前端构建工具

一、前端构建工具概述​ 前端构建工具是辅助开发者将源代码转换为浏览器可直接运行的静态资源的工具集合。随着前端技术的发展&#xff0c;源代码往往包含浏览器无法直接解析的语法&#xff08;如 TypeScript、Sass&#xff09;、模块化规范&#xff08;如 ES Modules、Common…

数据取证:Elcomsoft Password Digger,解密 macOS (OS X) 钥匙串信息

Elcomsoft Password Digger&#xff08;EPD&#xff09;是一款在 Windows 平台上使用的工具&#xff0c;用于解密存储在 macOS 钥匙串中的信息。该工具可以将加密的钥匙串内容导出到一个纯文本 XML 文件中&#xff0c;方便查看和分析。一键字典构建功能可以将钥匙串中的所有密码…

2.JVM跨平台原理(字节码机制)

目录引言一、跨平台就跟国际语言翻译似的二、字节码和 JVM 到底是啥玩意儿三、解决 “语言不通” 这个老难题四、实现 “一次编写&#xff0c;到处运行” 就这四步五、字节码技术给世界带来的大改变总结引言 咱平常是不是老纳闷儿&#xff0c;为啥同一个 Java 程序&#xff0c…

06-ES6

微任务&宏任务JS是单线程执行。所有要执行的任务都要排队。所有的同步任务会在主线程上排队&#xff0c;等待执行。异步任务&#xff1a;不会进入主线程&#xff0c;而是会进入任务队列。等到主线程上的任务执行完成之后&#xff0c;通知任务队列&#xff0c;执行异步任务。…

FreeSWITCH配置文件解析(10) 配置IP封禁(防暴力破解)

以下是针对FreeSWITCH配置IP封禁&#xff08;防暴力破解&#xff09;的完整方案&#xff0c;结合Fail2Ban与系统级防护策略&#xff1a;一、Fail2Ban核心配置&#xff08;推荐方案&#xff09;​​启用FreeSWITCH鉴权日志​​修改SIP Profile&#xff08;conf/sip_profiles/int…

【React 入门系列】React 组件通讯与生命周期详解

&#x1f9e9; 第一章&#xff1a;组件通讯概述在 React 开发中&#xff0c;组件是封装的、独立的功能单元。为了实现组件间的数据共享与协作&#xff0c;需要通过组件通讯机制。组件通讯的意义&#xff1a; 让多个封闭的组件能够共享数据&#xff0c;实现协作功能。&#x1f4…

前端开发 Vue 状态优化

Vue 项目中的状态优化一般都会用Pinia替代Vuex&#xff0c;Pinia 是 Vue 生态系统中的一个轻量级状态管理库&#xff0c;作为 Vuex 的替代品&#xff0c;它提供了更简洁的 API 和更好的性能。模块化管理&#xff1a;使用 Pinia 时&#xff0c;建议将状态拆分为多个 store 模块&…

虚幻基础:创建角色——FPS

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录创建角色设置模型添加摄像机添加位置&#xff1a;插槽弹簧臂&#xff1a;伸缩防止由碰撞导致摄像机穿模摄像机添加武器添加位置&#xff1a;插槽创建动画蓝图&#xff1a;主动获取角色数据并播放相应动画设置角色控制…