【c++11线程库的使用】

#include<iostream>
#include<thread>
#include<string>
using namespace std;
void hello(string msg) {
    for (int i = 0; i < 1000; i++) {
        cout << i;
        cout << endl;
    }
}
int main() {
    //1.创建线程
    thread thread1(hello,"hello Thread");//打印的就是hello Thread
    //主程序等待  看我这个程序运行完了吗
    //第三个知识点:thread1.join();//当上一个线程没有结束之前主线程是不会结束的
    //主线程结束之后我的线程依然可以再后台运行 那就是分离线程detach()
    //第四个知识点:thread1.detach();//这个就是主线程和子线程分离
    //第五个知识点:
    bool isJoin = thread1.joinable();//针对一个线程,可以调用detach,或者join。两者是互斥的关系,
    //也就说一旦调用了join,detach就不能再调用了,反之亦成立。
    //判断是否已经使用过join或者detach可以用joinable。
    if (isJoin) {
        thread1.join();
    }
    cout << "over" << endl;
    return 0;
}

std::ref传递引用类型

 #include<iostream>#include<thread>#include<string>using namespace std;void foo(int& x) {x += 1;}int main() {int a = 1;//thread t(foo, 1);//这个1不是引用是临时变量穿不进去  就释放掉了//所以要用ref  修饰这个a证明这个a就是它需要的引用变量thread t(foo, ref(a));t.join();cout << a << endl;return 0;}

类成员函数作为入口函数,类对象被提前释放

  错误示例:#include <iostream>#include <thread>​class MyClass {public:void func() {std::cout << "Thread " << std::this_thread::get_id() << " started" << std::endl;// do some workstd::cout << "Thread " << std::this_thread::get_id() //线程的信息<< " finished" << std::endl;}};​int main() {MyClass obj;std::thread t(&MyClass::func, &obj);// obj 被提前销毁了,会导致未定义的行为return 0;}

上面的代码中,在创建线程之后,obj 对象立即被销毁了,这会导致在线程执行时无法访问 obj 对象,可能会导致程序崩溃或者产生未定义的行为。

为了避免这个问题,可以使用 std::shared_ptr 来管理类对象的生命周期,确保在线程执行期间对象不会被销毁。具体来说,可以在创建线程之前,将类对象的指针封装在一个 std::shared_ptr 对象中,并将其作为参数传递给线程。这样,在线程执行期间,即使类对象的所有者释放了其所有权,std::shared_ptr 仍然会保持对象的生命周期,直到线程结束。

 #include<iostream>#include<thread>#include<string>#include<memory>using namespace std;class A {public:void foo() {cout << "hello world" << endl;;}};int main() {shared_ptr<A> a = make_shared<A>();//这个指针就是一直有效的//如果使用指针就还得手动释放内存  就很麻烦所以用智能指针//不需要这个变量的时候就释放掉thread t(&A::foo, a); // 这个指针就是一直有效的t.join();return 0;}

互斥量解决多线程数据共享问题

数据共享问题分析

在多个线程中共享数据时,需要注意线程安全问题。如果多个线程同时访问同一个变量,并且其中至少有一个线程对该变量进行了写操作,那么就会出现数据竞争问题。数据竞争可能会导致程序崩溃、产生未定义的结果,或者得到错误的结果。

为了避免数据竞争问题,需要使用同步机制来确保多个线程之间对共享数据的访问是安全的。常见的同步机制包括互斥量、条件变量、原子操作等。

 //这个就是互相抢夺资源的代码#include<iostream>#include<thread>#include<string>#include<memory>using namespace std;int a = 0;void foo() {for (int i = 0; i <= 10000; i++) {a += 1;}}int main() {thread t1(foo);thread t2(foo);​t1.join();t2.join();cout << a << endl;//输出17520  预期结果是20000 这就是互相抢夺资源了return 0;}

互斥锁解决

 #include<iostream>#include<thread>#include<string>#include<memory>#include<mutex>using namespace std;int a = 0;mutex mtx;void foo() {for (int i = 0; i < 10000; i++) {mtx.lock();//lock枷锁操作 如果不解锁其它线程是不能执行下面操作的a += 1;mtx.unlock();}}int main() {thread t1(foo);thread t2(foo);​t1.join();t2.join();cout << a << endl;//输出是20000 return 0;}

互斥量死锁

 //这就是死锁  死锁就是func_1在等着m2的所有权  func_2在等着m1的所有权  但是他俩都再互相等所以就没有释放彼此的锁就产生了死锁#include<iostream>#include<thread>#include<mutex>using namespace std;​mutex m1,m2;void func_1() {for (int i = 0; i < 50; i++) {m1.lock();m2.lock();m1.unlock();m2.unlock();​}}void func_2() {for (int i = 0; i < 50; i++) {m2.lock();m1.lock();m2.unlock();m1.unlock();​}}int main() {thread t1(func_1);thread t2(func_2);​t1.join();t2.join();cout << "over" << endl;return 0;}
lock_guard 与 std::unique_lock

lock_guard的特点:

  • 当构造函数被调用时,该互斥锁会被自动锁定

  • 当析构函数被调用时,该互斥锁会被自动解锁

  • lock_guard对象不能复制或移动,因此只能在局部作用域中使用

 #include<iostream>#include<thread>#include<string>#include<memory>#include<mutex>using namespace std;int a = 0;mutex mtx;void foo() {for (int i = 0; i < 10000; i++) {lock_guard<mutex>lg(mtx);a += 1;}}int main() {thread t1(foo);thread t2(foo);​t1.join();t2.join();cout << a << endl;//输出20000 return 0;}

unique_lock:

std:: 是 C++ 标准库中提供的一个互斥量封装类,用于在多线程程序中对互斥量进行加锁和解锁操作。它的主要特点是可以对互斥量进行更加灵活的管理,包括延迟加锁、条件变量、超时等。

std::unique_lock 提供了以下几个成员函数:

 `lock()`:尝试对互斥量进行加锁操作,如果当前互斥量已经被其他线程持有,则当前线程会被阻塞,直到互斥量被成功加锁。​`try_lock()`:尝试对互斥量进行加锁操作,如果当前互斥量已经被其他线程持有,则函数立即返回 `false`,否则返回 `true`。​`try_lock_for(const std::chrono::duration<Rep, Period>& rel_time)`:尝试对互斥量进行加锁操作,如果当前互斥量已经被其他线程持有,则当前线程会被阻塞,直到互斥量被成功加锁,或者超过了指定的时间。​`try_lock_until(const std::chrono::time_point<Clock, Duration>& abs_time)`:尝试对互斥量进行加锁操作,如果当前互斥量已经被其他线程持有,则当前线程会被阻塞,直到互斥量被成功加锁,或者超过了指定的时间点。​`unlock()`:对互斥量进行解锁操作。

单例设计模式

单例设计模式是一种常见的设计模式,用于确保某个类只能创建一个实例。由于单例实例是全局唯一的,因此在多线程环境中使用单例模式时,需要考虑线程安全的问题。

下面是一个简单的单例模式的实现:

 #include<iostream>#include<thread>#include<string>#include<memory>#include<mutex>using namespace std;​//日志功能就是单例模式 class Log {public:Log() {};Log(const Log& log) = delete;//在某些情况下,我们希望类的实例只能有一个。通过禁用拷贝构造函数,我们可以确保不会创建多个相同的实例。Log& operator = (const Log& log) = delete; ​static Log& GetInstance() {//这样写就是全局只有一个log不会有第二个这就是懒汉模式//提前构造了一个对象 需要的时候就返回这个对象static Log log;return log;/** static Log *log = nullptr;//饿汉模式* if(!log) log = new Log;* return *log;//提前不声明指针,需要的时候才创建对象*/}void PrintLog(string msg) {cout << msg << endl;​}};int main() {Log::GetInstance().PrintLog("error");return 0;}

call_once知识

多线程在单例模式中出现的一个问题:就是一下代码因为是单例模式但是线程调用两个线程是并行的 那就声明了两次

 ​#include<iostream>#include<thread>#include<string>#include<memory>#include<mutex>using namespace std;​//日志功能就是单例模式 class Log {public:Log() {};Log(const Log& log) = delete;Log& operator = (const Log& log) = delete; ​static Log& GetInstance() {//这样写就是全局只有一个log不会有第二个这就是懒汉模式//提前构造了一个对象 需要的时候就返回这个对象static Log log;return log;/** static Log *log = nullptr;//饿汉模式* if(!log) log = new Log;* return *log;//提前不声明指针,需要的时候才创建对象*/}void PrintLog(string msg) {cout << msg << endl;​}};void printError() {Log::GetInstance().PrintLog("error");}int main() {thread t1(printError);thread t2(printError);t1.join();t2.join();​return 0;}

我们就用call_once解决

 #include<iostream>#include<thread>#include<string>#include<memory>#include<mutex>using namespace std;​//日志功能就是单例模式 static Log* log = nullptr;//饿汉模式static once_flag once;class Log {public:Log() {};Log(const Log& log) = delete;Log& operator = (const Log& log) = delete; ​static Log& GetInstance() {//这样写就是全局只有一个log不会有第二个这就是懒汉模式提前构造了一个对象 需要的时候就返回这个对象//static Log log;//return log;if(!log) log = new Log;call_once(once, init);return *log;//提前不声明指针,需要的时候才创建对象}void PrintLog(string msg) {cout << msg << endl;​}static void init() {if (!log) log = new Log;}   };void printError() {Log::GetInstance().PrintLog("error");}int main() {thread t1(printError);thread t2(printError);t1.join();t2.join();​return 0;}

线程池的使用 写的

必要的东西:- 一个线程数组(维护一堆线程)
- 任务队列
- 用户 /生产者向队列里加任务
- 线程数组派线程取任务```
#include<iostream>
#include<thread>
#include<string>
#include<memory>
#include<mutex>
#include<condition_variable>
#include<queue>
#include<vector>
using namespace std;
#include<functional>
class ThreadPool {
public:ThreadPool(int numThreads) :stop(false) {for (int i = 0; i < numThreads; i++) {threads.emplace_back([this] {//添加任务  用了拉姆达表达式while (1) {unique_lock<mutex> lock(mtx);condition.wait(lock, [this] {//判断任务队列里面有没有任务 有就取return !tasks.empty() || stop;});if (stop && tasks.empty()) {return;}function<void()> task(move(tasks.front()));}});}}~ThreadPool() {{unique_lock<mutex> lock(mtx);stop = true;//代表线程结束了}condition.notify_all();for (auto& t : threads) {//自动类型推导 自动判断这个数组里面是什么类型t.join();}}template<class F,class... Args>void enqueue(F &&f,Args&&... args) {function<void()> task =bind(forward<F>(f),forward<Args>(args)...);{unique_lock<mutex> lock(mtx);tasks.emplace(move(task));}condition.notify_one();}
private:vector<thread> threads;//线程数组queue<function<void()>> tasks;mutex mtx;condition_variable condition;//条件变量bool stop;//线程池什么时候终止};
int main() {ThreadPool pool(4);for (int i = 0; i < 10; i++) {pool.enqueue([i]() {cout << "第几个任务" << i << "任务开始" << endl;this_thread::sleep_for(chrono::seconds(1));cout << "第几个任务" << i << "任务结束" << endl;});}return 0;}```

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

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

相关文章

STM32---通用定时器(一)理论基础

写在前面&#xff1a;在STM32F103中有众多的定时器&#xff0c;其中包括两个基本定时器&#xff0c;基本定时器的内容已经在上节进行了介绍&#xff0c;基本定时器的功能、结构、使用都较为简单。而STM32F1中还含有4个通用定时器&#xff08;TIM2\3\4\5&#xff09;,这些定时器…

GEE案例——如何对矢量集合(面状)提取中心点并返回给矢量(添加经纬度属性信息)

简介 很多时候我们会遇到一个需求,就是将我们已经获取的矢量集合进行一个中心点经纬度的获取,这个过程,最简单的方式就是通过我们一个个通过交互式的地图去点击,查看获取,但是这样的工作量有点大,而很多时候我们分解出的矢量是超级多的,比如说上百个成千个,这对于我们…

探讨系统测试的最佳实践与思维模式!

这是测试活动过程详解系列的最后一篇文章。之前的想法&#xff0c;是对测试过程各重要环节进行拆解&#xff0c;然后介绍这个环节重点要做的事情&#xff0c;为什么要做这些事&#xff0c;以及注意事项。 前面几篇文章分别介绍了单元测试、集成测试、回归测试阶段要解决的问题…

WebStorm 开启 eslint 自动格式化配置

之后在 ctrl s保存之后&#xff0c;webstorm 都会根据eslint 的规则自动格式化。

长见识了Python闭包函数

1.闭包 如果一个函数内部定义了另外一个函数&#xff0c;那么外边的函数叫做外函数&#xff0c;内部的函数叫做内函数 如果在一个外部函数当中定义了一个内部函数&#xff0c;并且外部函数的返回值是内部函数&#xff0c;这就构成了一个闭包&#xff0c;内部函数被称为闭包函数…

计算机等级考试:信息安全技术 知识的四

1、ISMS所体现的思想是预防控制为主 2、电子认证服务提供者应当妥善保存与认证相关的信息&#xff0c;信息保存期限至少为电子签名认证证书失效后5年。 3、《电子签名法》 第二十三条&#xff0c;电子认证服务提供者拟暂停或者终止电子认证服务的&#xff0c;应当在暂停或者终…

子类的继承性

继承性 类有两种重要的成员&#xff1a; 成员变量和方法 子类的成员 ① 自己声明定义 ②从父类继承 ① 成员变量的继 把继承来的变量作为 自己的一个成员变量 &#xff08;如同在子类中直接声明一样&#xff09;&#xff1b; 可被子类中自定义的任何实例方法操作 。 ② 方法…

实验一:华为VRP系统的基本操作

1.1实验介绍 1.1.1关于本实验 本实验通过配置华为设备&#xff0c;了解并熟悉华为VRP系统的基本操作 1.1.2实验目的 理解命令行视图的含义以及进入离开命令行视图的方法 掌握一些常见的命令 掌握命令行在线帮助的方法 掌握如何撤销命令 掌握如何使用命令快捷键 1.1.3实验组网 …

Java算法-力扣leetcode-45. 跳跃游戏 II

一、java8原子类LongAdder 在Java并发编程(2)中有关于AtomicInteger的介绍. AtomicInteger通过CAS非阻塞的原子操作提升了并发性能. 但随着线程数量增大对共享资源的竞争提升,大量线程竞争失败会进入到自旋中,消耗了cpu资源. JDK8中新增了原子类LongAdder, 弥补AtomicLong的上…

人不想做事情的时候,可能是他/她正在经历情绪

目录 情绪是什么? 计算机也有“情绪”? 情绪如何影响人的行为? 受情绪困扰时人为何不想做事? 如何排解情绪困扰?

基于javaweb+springboot开发的城市地名地址信息管理系统设计和实现

基于javaweb(springboot)城市地名地址信息管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言…

基于GAN对抗网进行图像修复

一、简介 使用PyTorch实现的生成对抗网络&#xff08;GAN&#xff09;模型&#xff0c;包括编码器&#xff08;Encoder&#xff09;、解码器&#xff08;Decoder&#xff09;、生成器&#xff08;ResnetGenerator&#xff09;和判别器&#xff08;Discriminator&#xff09;。…

Dubbo的线程池策略

1 Dubbo的线程池概述 这里将要讲述的线程池指Dubbo服务端使用某些线程模型&#xff08;如 all 模型&#xff09;时用到的业务线程池。ThreadPool 是一个扩展接口SPI。 SPI(value "fixed", scope ExtensionScope.FRAMEWORK) public interface ThreadPool {/*** Th…

基于深度学习的苹果叶片病害检测系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 可以任意更换主干结构&#xff0c;支持几百种网络主干。 数据集&#xff1a;     网上下载的数据集&#x…

基于极大似然算法的系统参数辨识matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于极大似然算法的系统参数辨识。对系统的参数a1&#xff0c;b1&#xff0c;a2&#xff0c;b2分别进行估计&#xff0c;计算估计误差以及估计收敛曲线&#xff0…

使用yarn创建vite+vue3electron多端运行

文章目录 第一步 使用yarn创建vite+vue3项目遇到创建报错看第二步 引入electron第三步 创建main.js在electron下面的main.js写入下面代码第四步 安装同时运行多条命令npm包&&修改package.json文件npm包增加一条electron运行脚本命令效果图第一步 使用yarn创建vite+vue3…

【pytorch可视化工具】

TensorboardX 在PyTorch中&#xff0c;模型训练的可视化通常通过TensorBoard或Visdom等工具实现。以下是如何使用TensorBoard进行模型训练可视化的步骤&#xff1a; 使用TensorboardX与PyTorch配合 确保已经安装了tensorboard和tensorboardX库。 pip install tensorboard p…

springboot Mongo大数据查询优化方案

前言 因为项目需要把传感器的数据保存起来&#xff0c;当时设计的时是mongo来存储&#xff0c;后期需要从mongo DB里查询传感器的数据记录。由于传感器每秒都会像mongo数据库存500条左右的数据&#xff0c;1天就有4320万条数据&#xff0c;要想按照时间条件去查询&#xff0c;…

【数据可视化】动手用matplotlib绘制关联规则网络图

下载文中数据、代码、绘图结果 文章目录 关于数据绘图函数完整可运行的代码运行结果 关于数据 如果想知道本文的关联规则数据是怎么来的&#xff0c;请阅读这篇文章 绘图函数 Python中似乎没有很方便的绘制网络图的函数。 下面是本人自行实现的绘图函数&#xff0c;如果想…

(每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理 第13章 项目资源管理(七)

项目建议与立项申请、初步可行性研究、详细可行性研究、评估与决策是项目投资前使其的四个阶段。在实际工作中&#xff0c;初步可行性研究和详细可行性研究可以依据项目的规模和繁简程度合二为一&#xff0c;但详细可行性研究是不可缺少的。升级改造项目制作初步和详细研究&…