C++多线程入门笔记

参考:
https://blog.csdn.net/qq_44891434/article/details/132559929
https://www.cnblogs.com/chen-cs/p/13055211.html

#include <thread>
std::thread t(function_name, args...);

function_name是线程入口点的函数或可调用对象
args…是传递给函数的参数,当调用的函数是无参的可以空着。
创建线程后,我们可以使用t.join()等待线程完成,join()函数的作用是让主线程的等待该子线程完成,然后主线程再继续执行
或者使用t.detach()分离线程,让它在后台运行。
一个子线程只能调用join()和detach()中的一个,且只允许调用一次。
使用**++ -std=c++11 -o thread thread.cpp -lpthread**编译

等待线程完成.join()

#include <iostream>
#include <thread>
void print_message(const std::string& message) {std::cout << message << std::endl;
}
void increment(int& x) {    ++x;
}
int main() {    std::string message = "Hello, world!";    std::thread t(print_message, message);    t.join();    int x = 0;    std::thread t2(increment, std::ref(x));    t2.join();    std::cout << x << std::endl;    return 0;
}

输出:

Hello, world!
1

分离线程.detach()

有时候我们可能不需要等待线程完成,而是希望它在后台运行。这时候我们可以使用t.detach()方法来分离线程。

#include <iostream>
#include <thread>
void print_message(const std::string& message) {    std::cout << message << std::endl;
}
int main() {    std::thread t(print_message, "Thread 1");    t.detach();    std::cout << "Thread detached" << std::endl;    return 0;
}

Thread detached
Thread 1

可以是主进程完成之后在进行子进程

线程是否被调用.joinable()

因为join和detach智能调用一次,所以可以使用joinable来判断是否可以使用该线程
针对一个线程,可以调用detach,或者join。两者是互斥的关系,也就说一旦调用了join,detach就不能再调用了,反之亦成立。判断是否已经使用过join或者detach可以用joinable。

	std::thread t(print_message, "Thread 1");    std::cout << t.joinable() << std::endl; t.join();    std::cout << "Thread detached" << std::endl;  std::cout << t.joinable() << std::endl;  

1
Thread 1
Thread detached
0

往线程里穿临时变量要用参考的方式引用

	int i=1;std::thread t(foo, std::ref(i)) #std::thread t(foo, 1);

如果是直接浅拷贝传递临时变量给线程,那么线程在执行的时候,临时变量会被销毁

互斥量mutex

当不同的线程同事访问改写一个数据的时候,就可能出现数据竞争的关系,为避免数据竞争问题,可以使用同步机制()包括互斥量、条件变量、原子操作)来保证访问安全。

void func(int n) {for (int i = 0; i < 10; ++i) {//mtx.lock();shared_data++;        std::cout << "Thread " << n << " increment shared_data to " << shared_data << std::endl;//mtx.unlock();}
}
int main() {std::thread t1(func, 1);std::thread t2(func, 2);

在不设置互斥锁的情况下,访问和修改是无序的

Thread 2 increment shared_data to 2
Thread 2 increment shared_data to 3
Thread 2 increment shared_data to 4
Thread 2 increment shared_data to 5
Thread 2 increment shared_data to 6
Thread 2 increment shared_data to 7
Thread 2 increment shared_data to 8
Thread 2 increment shared_data to 9
Thread 2 increment shared_data to 10
Thread 2 increment shared_data to 11
Thread 1 increment shared_data to 11
Thread 1 increment shared_data to 12
Thread 1 increment shared_data to 13
Thread 1 increment shared_data to 14
Thread 1 increment shared_data to 15
Thread 1 increment shared_data to 16
Thread 1 increment shared_data to 17
Thread 1 increment shared_data to 18
Thread 1 increment shared_data to 19
Thread 1 increment shared_data to 20

先调用 mtx.lock() 来获取互斥量的所有权,然后对 shared_data 变量进行累加操作,最后再调用 mtx.unlock() 来释放互斥量的所有权。

互斥量死锁

假设有两个线程 T1 和 T2,它们需要对两个互斥量 mtx1 和 mtx2 进行访问,而且需要按照以下顺序获取互斥量的所有权:

T1 先获取 mtx1 的所有权,再获取 mtx2 的所有权。
T2 先获取 mtx2 的所有权,再获取 mtx1 的所有权。

当两个都在等对方释放资源的时候就可能会造成死锁

void func1() {    mtx2.lock();    std::cout << "Thread 1 locked mutex 2" << std::endl;    mtx1.lock();    std::cout << "Thread 1 locked mutex 1" << std::endl;    mtx1.unlock();    std::cout << "Thread 1 unlocked mutex 1" << std::endl;    mtx2.unlock();    std::cout << "Thread 1 unlocked mutex 2" << std::endl;
}
void func2() {    mtx2.lock();    std::cout << "Thread 2 locked mutex 2" << std::endl;    mtx1.lock();    std::cout << "Thread 2 locked mutex 1" << std::endl;    mtx1.unlock();    std::cout << "Thread 2 unlocked mutex 1" << std::endl;    mtx2.unlock();    std::cout << "Thread 2 unlocked mutex 2" << std::endl;
}

在上述实例中,两者都先强调mtx2,再强调mtx1,所以谁先抢到mtx2谁先执行,还有个函数try_lock()其功能和joinable差不多。

Thread 1 locked mutex 2
Thread 1 locked mutex 1
Thread 1 unlocked mutex 1
Thread 1 unlocked mutex 2
Thread 2 locked mutex 2
Thread 2 locked mutex 1
Thread 2 unlocked mutex 1
Thread 2 unlocked mutex 2

原子操作

指事务的不可分割性,一个事务的所有操作要么不间断地全部被执行,要么一个也没有执行。
其定义方式atomic x,在对它进行操作是原子性的,不会出现数据竞争问题

#include <atomic>
#include <iostream>
#include <thread>
std::atomic<int> count = 0;
void increment() {for (int i = 0; i < 1000000; ++i) {count++;}
}
int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << count << std::endl;return 0;
}

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

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

相关文章

【Spark精讲】一文讲透SparkSQL执行过程

SparkSQL执行过程 逻辑计划 逻辑计划阶段会将用户所写的 SQL语句转换成树型数据结构(逻辑算子树)&#xff0c; SQL语句中蕴含的逻辑映射到逻辑算子树的不同节点。 顾名思义&#xff0c;逻辑计划阶段生成的逻辑算子树并不会直接提交执行&#xff0c;仅作为中间阶段 。 最终逻辑…

c# 设置文件夹隐藏

在C#中&#xff0c;你可以使用DirectoryInfo类的Attributes属性来设置文件夹的隐藏属性。以下是一个示例代码&#xff1a; using System; using System.IO;class Program {static void Main(string[] args){string folderPath "你的文件夹路径"; // 替换为你要隐藏…

二、KMDF开发之HelloWord

目录 第一步、创建KMDF项目 第二步、代码里增加打印信息 最终我们是要自己开发PCIE驱动&#xff0c;这里使用HelloWord工程把整个环境打通&#xff0c;下一篇将讲KMDF双机调试环境的搭建&#xff0c;开发环境的搭建见上一篇博文《一、KMDF开发之环境搭建-CSDN博客》。 第一步…

关键字:abstract关键字

在 Java 中&#xff0c;abstract是一个关键字&#xff0c;用于修饰类和方法。当一个类被声明为抽象类时&#xff0c;它不能被实例化&#xff0c;只能被其他类继承。同时&#xff0c;抽象类可以包含抽象方法&#xff0c;抽象方法没有方法体&#xff0c;只包含方法的签名&#xf…

docker-compose 安装gitlab

写在前面的话&#xff1a;docker-compose的文件是通用的&#xff0c;因此可以切换任意版本的gitlab的镜像版本。 往期docker-compose部署系列如&#xff1a; docker-compose语法格式docker-compose部署openldapdocker-compose 安装Sonar并集成gitlab 文章目录 1. 参考文档2. 环…

java spring boot 自定义 aop

以一个锁的加锁和释放为例 1、先定义注解 /*** 锁切面* author fmj*/ Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface VersionLockAOP { }2、然后定义切面类以及切点 /*** 切面*/ Component Aspect Slf4j public class VersionLockAOPAspe…

Spring AOP<一>简介与基础使用

spring AOP 基础定义 含义使用切面组织多个Advice,Advice放在切面中定义。也就是说是定义通知的自定义类。自定义的AOP类Aspect连接点方法调用&#xff0c;异常抛出可以增强的点JoinPoint &#xff1a;也就是**被增强的方法的总称&#xff0c;可以获取具体方法的信息&#xff…

SSRF靶场安装测试记录

目录 环境 靶场介绍 1. 获取并显示指定文件内容的应用程序代码

Navicat删除连接报错:service in use cannot be deleted的解决方法

我在删除连接时遇到了这个报错&#xff0c;内容如图。下面我介绍两种解决方法&#xff0c;非常简单。 第一种 右键点击想要删除的连接&#xff0c;先选择“关闭连接”。再选择“删除连接” 第二种 如果第一种方法无效&#xff0c;直接关闭Navicat软件&#xff0c;重新打开。然后…

WPF 基础入门(样式)

3.1 一般样式 <Grid Margin"10"><TextBlock Text"Style test" Foreground"Red" FontSize"20"/> </Grid> 3.2内嵌样式 直接在控件上定义样式&#xff0c;如下所示&#xff1a; <Grid Margin"10">…

【c/c++】指针例图基础详解

文章目录 指针变量内存指针详解例1例2练习&答案解析 指针变量内存 int main(){// 各类型变量占字节数printf("char: %d\n",sizeof(char)); // 1printf("short: %d\n",sizeof(short)); // 2printf("int: %d\n",sizeof(int)); // 4pri…

uniapp多级动态表单规则

最近有个新的业务、主要涉及多层级的动态表单提交&#xff0c;其中又涉及很多类型&#xff0c;踩了很多坑之后&#xff0c;终于研发完毕。 传来的数据格式处理 传来的数据格式涉及比较多的内容&#xff0c;以下举例一个&#xff0c;涉及到规则的填写 规则写法有两种&#xff…

算法基础之蒙德里安的梦想

蒙德里安的梦想 核心思想&#xff1a; 状态压缩dp 总方案 横放的方案 剩下的地方竖着放是固定的了 状态压缩 &#xff1a; 将每一列的图(横终点 横起点 竖) 用一个二进制数存下 向后凸的为1 反之为0 状态计算&#xff1a; 所有 i – 1 列 不冲突的 都加和 f[i , j] f[i - 1…

lodop打印控件使用

功能演示 - Lodop和C-Lodop官网主站 云官网 : Lodop和C-Lodop官网主站 官网 : Lodop和C-Lodop官网主站 &#xff08;建议网速不怎么样的&#xff0c;不要使用这个网站了&#xff09; 这个就不用多讲了&#xff0c;当然云官网的速度要快一些&#xff0c;里面的内容展示方式都是…

小程序域名SSL证书能否用免费的?

在小程序开发中&#xff0c;确保通信安全性是至关重要的一环&#xff0c;而SSL证书正是为此提供了有效的保障。SSL证书通过加密数据传输&#xff0c;防止数据被中间人恶意窃取或篡改&#xff0c;为用户和应用提供了更安全的通信环境。 针对小程序域名的SSL证书&#xff0c;通常…

【HTML5】第1章 HTML5入门

学习目标 了解网页基本概念&#xff0c;能够说出网页的构成以及网页相关名词的含义 熟悉Web标准&#xff0c;能够归纳Web标准的构成。 了解浏览器&#xff0c;能够说出各主流浏览器的特点。 了解HTML5技术&#xff0c;能够知道HTML5发展历程、优势以及浏览器对HTML5的支持情…

PINNs解麦克斯韦方程

1 问题介绍 麦克斯韦方程控制着光的传播及其与物质的相互作用。因此&#xff0c;利用计算电磁学模拟求解麦克斯韦方程对理解光与物质相互作用和设计光学元件起着至关重要的作用。对于线性、非磁性、各向同性材料没有电、磁电流密度的方程通常可以写成如下形式&#xff1a; 2 物…

C# WPF上位机开发(Web API联调)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多时候&#xff0c;客户需要开发的不仅仅是一个上位机系统&#xff0c;它还有其他很多配套的系统或设备&#xff0c;比如物流小车、立库、数字孪…

【toolschain】关于anaconda安装包时候 系统级全局安装还是安装在虚拟环境里的问题总结

关于安装方式决定所被安装环境的问题 借机会研究了一下 关于处在anaconda虚拟环境下的 安装方式的不同 安装路径不同的问题&#xff0c;并总结如下原则&#xff1a; conda 无法管理或者conda库查不到的&#xff0c;自然只能通过其他方式安装&#xff0c;那么路径就不在虚拟环…

CentOS安装Maven教程-shell脚本一键安装配置

文章目录 前言一、Maven安装教程1. 确认系统环境2. 下载和解压Maven3. 配置环境变量4. 验证安装5. 设置镜像站 二、Maven安装教程&#xff08;使用shell脚本一键安装配置&#xff09;1. 复制脚本2. 增加执行权限3. 执行脚本4. 加载用户环境变量 总结 前言 本教程将介绍如何在C…