C++并发编程

基本介绍

线程

  • C++98标准没有直接提供原生的多线程支持

  • 在C++98中,并没有像后来的C++11标准中那样的<thread>库或其他直接的多线程工具

  • 然而,这并不意味着在C++98中无法实现多线程。开发者通常会使用平台特定的API(如Windows的线程API或POSIX线程(pthreads))来实现多线程。此外,一些第三方库,如Boost.Thread,也提供了在C++98环境中进行多线程编程的功能

  • 需要注意的是,使用平台特定的API或第三方库进行多线程编程可能会增加代码的复杂性和维护成本,因为你需要确保你的代码在所有目标平台上都能正常工作,并处理各种可能的线程同步和互斥问题

  • 从C++11开始,C++标准库开始直接支持多线程编程,通过引入<thread><mutex><condition_variable>等头文件,提供了更为方便和统一的多线程编程接口。因此,如果可能的话,建议使用C++11或更高版本的C++标准进行多线程编程

进程

  • C++标准库本身并没有直接提供创建进程的功能,创建进程通常依赖于操作系统的API或其他库函数

  • 在Unix和Linux系统中,可以使用fork()函数来创建进程。fork()函数会创建一个与当前进程几乎完全相同的子进程,包括代码、数据和堆栈等。在子进程中,可以使用exec()系列函数来执行另一个程序

  • 在Windows系统中,可以使用CreateProcess()函数来创建进程。这个函数会创建一个新的进程,并返回一个进程句柄,可以用于操作该进程

创建线程

#include<iostream>
#include<string>
#include<thread>void printHelloWorld()
{std::cout << "Hello World" << std::endl;
}void print(std::string text)
{std::cout << text << std::endl;
}int main()
{// 当前 main 这里是主线程// 创建一个线程 t1,让它执行 printHelloWorld 这个函数std::thread t1(printHelloWorld);// 等待 t1 线程完成(如果不等待,可能子线程 t1 还没完成的时候,主线程已经结束了,程序会报错)t1.join();// 创建一个线程 t2,让它执行 print 这个函数,并传入参数std::thread t2(print, "This is thread 2.");// 等待 t2 线程完成(如果不等待,可能子线程 t2 还没完成的时候,主线程已经结束了,程序会报错)t2.join();// 创建一个线程 t3std::thread t3(print, "This is thread 3.");// 分离线程(也可以使用分离线程这个技术,让主线程结束后,子线程依然可以运行)t3.detach();// 创建一个线程 t4std::thread t3(print, "This is thread 3.");// 严谨的项目里面,可能用到,先判断该线程是否可以被join()bool isJoin = t3.joinable();if (isJoin){t3.join();}return 0;
}

线程常见错误

  1. 传递临时变量的问题
#include<iostream>
#include<thread>void foo(int& x)
{x += 1;
}int main()
{int num = 1;		// 局部变量 numstd::thread t1(foo, std::ref(num));		// std::ref() 传递引用类型t1.join();		// 等待t1线程结束std::cout << num << std::endl;return 0;
}
  1. 传递指针或引用指向局部变量的问题
#include<iostream>
#include<thread>// 创建一个线程 t (全局变量)
std::thread t;
int a = 1;void foo(int& x)
{std::cout << x << std::endl;		// 1x += 1;std::cout << x << std::endl;		// 2
}void test()
{t = std::thread(foo, std::ref(a));
}int main()
{test();t.join();return 0;
}
  1. 入口函数为类的私有成员函数
#include<iostream>
#include<thread>
#include<memory>	// 智能指针,不用的时候,会自动释放class A
{
private:friend void thread_foo();void foo(){std::cout << "hello" << std::endl;}
};void thread_foo()
{std::shared_ptr<A> a = std::make_shared<A>();	// 使用智能指针实例化A对象std::thread t(&A::foo, a);t.join();
}int main()
{thread_foo();
}

互斥量

锁的使用

#include<iostream>
#include<thread>
#include<mutex>int a = 0;// 创建互斥锁
std::mutex mtx;void func()
{for (int i = 0; i < 10000; i++){mtx.lock();		// 加锁a += 1;mtx.unlock();	// 解锁}
}int main()
{std::thread t1(func);std::thread t2(func);t1.join();t2.join();std::cout << a << std::endl;return 0;
}

死锁演示

  • 图形演示

在这里插入图片描述

  • 代码演示
#include<iostream>
#include<thread>
#include<mutex>// 创建互斥锁
std::mutex mtx1;
std::mutex mtx2;// people1 先抢占 mtx1,再快速抢占 mtx2
void people1()
{for (int i = 0; i < 1000; i++){mtx1.lock();std::cout << "people1 上锁mtx1成功\n";mtx2.lock();std::cout << "people1 上锁mtx2成功\n";mtx1.unlock();mtx2.unlock();}
}// people2 先抢占 mtx2,再快速抢占 mtx1
void people2()
{for (int i = 0; i < 1000; i++){mtx2.lock();std::cout << "people2 上锁mtx2成功\n";mtx1.lock();std::cout << "people2 上锁mtx1成功\n";mtx1.unlock();mtx2.unlock();}
}int main()
{std::thread t1(people1);std::thread t2(people2);t1.join();t2.join();return 0;
}

解决死锁

  • 解决办法:所有人都要严格按照顺序抢占资源,都要先抢占完A资源,才能继续抢占B资源,继续抢占C资源…
#include<iostream>
#include<thread>
#include<mutex>// 创建互斥锁
std::mutex mtx1;
std::mutex mtx2;// people1 要先抢占 mtx1,才能抢占 mtx2
void people1()
{for (int i = 0; i < 1000; i++){mtx1.lock();std::cout << "people1 上锁mtx1成功\n";mtx2.lock();std::cout << "people1 上锁mtx2成功\n";mtx1.unlock();std::cout << "people1 解锁mtx1成功\n";mtx2.unlock();std::cout << "people1 解锁mtx2成功\n";}
}// people2 要先抢占 mtx1,才能抢占 mtx2
void people2()
{for (int i = 0; i < 1000; i++){mtx1.lock();std::cout << "people2 上锁mtx1成功\n";mtx2.lock();std::cout << "people2 上锁mtx2成功\n";mtx1.unlock();std::cout << "people2 解锁mtx1成功\n";mtx2.unlock();std::cout << "people2 解锁mtx2成功\n";}
}int main()
{std::thread t1(people1);std::thread t2(people2);t1.join();t2.join();return 0;
}

lock_guard

  • std::lock_guard 是 C++ 标准库中的一种互斥量封装类,用于保护共享数据,防止多个线程同时访问同一资源而导致的数据竞争问题
  • 当构造函数被调用时,该互斥量会被自动锁定
  • 当析构函数被调用时,该互斥量会被自动解锁
  • std::lock_guard 对象不能复制或移动,因此它只能在局部作用域中使用
#include<iostream>
#include<thread>
#include<mutex>// 共享变量
int shared_data = 0;// 创建互斥锁
std::mutex mtx;void func()
{for (int i = 0; i < 1000; i++){std::lock_guard<std::mutex> obj(mtx);	// 构造时自动加锁,析构时自动解锁shared_data++;}
}int main()
{std::thread t1(func);std::thread t2(func);t1.join();t2.join();std::cout << shared_data << std::endl;		// 2000return 0;
}

unique_lock

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

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

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

std::unique_lock 还提供了以下几个构造函数

unique_lock() noexcept = default:默认构造函数,创建一个未关联任何互斥量的 std::unique_lock 对象explicit unique_lock(mutex_type& m):构造函数,使用给定的互斥量 m 进行初始化,并对该互斥量进行加锁操作unique_lock(mutex_type& m, defer_lock_t) noexcept:构造函数,使用给定的互斥量 m 进行初始化,但不对该互斥量进行加锁操作unique_lock(mutex_type& m, try_to_lock_t) noexcept:构造函数,使用给定的互斥量 m 进行初始化,并尝试对该互斥量进行加锁操作。如果加锁失败,则创建的 std::unique_lock 对象不与任何互斥量关联unique_lock(mutex_type& m, adopt_lock_t) noexcept:构造函数,使用给定的互斥量 m 进行初始化,并假设该互斥量已经被当前线程成功加锁

文章推荐

  • std::thread 快速上手:https://blog.csdn.net/m0_75215937/article/details/135007590
  • std::thread 更多内容:https://blog.csdn.net/sjc_0910/article/details/118861539
  • c++ 多线程编程:https://zhuanlan.zhihu.com/p/547312117

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

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

相关文章

el-tree 或 el-tree-select 根据条件,控制节点的显示隐藏

目录 情况概述方案&#xff1a;render-content&#xff08;树节点的内容区的渲染 Function&#xff09;代码如下 情况概述 要求el-tree-select 中的节点 根据节点状态来进行显示隐藏&#xff08;状态字段为status&#xff0c;显示&#xff1a;‘1’&#xff0c;隐藏&#xff1…

vmware workstation使用心得

1 启动虚拟机windows系统立即蓝屏 windows未开启虚拟化 vmware workstation与windows系统不兼容 下载兼容版本的vmware workstationwindow10若最新&#xff0c;升级vmware workstation 到15.5.7 排除不兼容的情况&#xff0c;windows系统自身虚拟化配置未开启&#xff1a; VMw…

vue3中的ref、isRef、shallowRef、triggerRef和customRef

1.ref 接受一个参数值并返回一个响应式且可改变的 ref 对象。 ref 对象拥有一个指向内部值的单一属性 .value property &#xff0c;指向内部值。 例&#xff1a;此时&#xff0c;页面上的 str1 也跟着变化 <template><div><button click"handleClick&quo…

如何在 windows 下运行 linux 程序

安装WSL和相关的Linux发行版可以按照以下步骤进行&#xff1a; 启用WSL功能&#xff1a; 打开“控制面板” -> “程序” -> “程序和功能” -> “启用或关闭Windows功能”。在弹出的窗口中&#xff0c;勾选“适用于Linux的Windows子系统”&#xff0c;然后点击“确定”…

严厉打击侵犯知识产权行为!法院公开审理假冒半岛超声炮知产刑事案件

随着医美行业的蓬勃发展&#xff0c;一些不法分子利用消费者对变美的渴望&#xff0c;制售假冒半岛超声炮&#xff0c;严重侵犯了消费者的合法权益&#xff0c;也破坏了医美市场的健康发展。为了维护市场秩序&#xff0c;保障消费者权益&#xff0c;各地相关监管部门持续加大监…

QT从入门到实战x篇_22_番外1_Qt事件系统

文章目录 1. Qt事件系统简介1.1 事件的来源和传递1.2 事件循环和事件分发1.2.1 QT消息/事件循环机制1.2.1.1 机制解释1.2.1.2 两个问题 1.2.2 事件分发 2. 事件过滤基础2.1 什么是事件过滤器&#xff08;Event Filter&#xff09;&#xff1f;2.2 如何安装事件过滤器 3. 事件过…

<计算机网络自顶向下> 路由器组成

路由器结构概况 路由&#xff1a;运行路由选择算法/协议&#xff08;RIP, OSPF, BGP&#xff09;生成路由表转发&#xff1a;从输入到输出链路交换数据包-根据路由表进行分组的转发中间的fabric是用来接收输入的分组交给输出端口的&#xff0c;完成局部的转发&#xff08;根据…

在广东珠海,持有软考等证书最高可获6位数补贴,快来申报!

近日&#xff0c;横琴粤澳深度合作区执行委员会印发《横琴粤澳深度合作区支持人才发展若干措施》&#xff08;以下简称《若干措施》&#xff09;及三项配套实施办法&#xff0c;鼓励企业“招贤纳士”&#xff0c;加强琴澳人才协同培养。目前&#xff0c;2024年第一批博士后专项…

Java23种设计模式-结构型模式之组合模式

组合模式&#xff08;Composite Pattern&#xff09;&#xff1a;将对象组合成树状结构以表示“部分-整体”层次结构&#xff0c;同时保持对单个对象和组合对象的一致性操作&#xff0c;主要目的是简化客户端代码&#xff0c;因为它可以统一处理单个对象和组合对象。 通常包含…

星汉未来AI应用市场:一站式AI解决方案平台

星汉未来AI应用市场&#xff1a;一站式AI解决方案平台 在人工智能技术日益渗透到各行各业的今天&#xff0c;星汉未来AI应用市场为我们提供了一个集创新与实用于一体的平台。下面&#xff0c;我将为您详细介绍这个平台的各个方面。 平台特色 星汉未来AI应用市场是一个面向未…

Keil出现警告:warning: #223-D: function “XXX“ declared implicitly

这个警告表明编译器在函数使用之前没有找到函数的显式声明或定义。这通常发生在函数被使用之前没有在当前文件中进行声明或定义&#xff0c;或者头文件未正确包含。 解决方式&#xff1a; 在当前文件中添加函数声明&#xff1a;在使用函数之前&#xff0c;在当前文件中添加函…

华为OD机试真题-反射计数-2023年OD统一考试(C卷D卷)

题目描述: 给定一个包含 0 和 1 的二维矩阵 给定一个初始位置和速度 一个物体从给定的初始位置触发, 在给定的速度下进行移动, 遇到矩阵的边缘则发生镜面反射 无论物体经过 0 还是 1, 都不影响其速度 请计算并给出经过 t 时间单位后, 物体经过 1 点的次数 矩阵以左上角位置为[…

maixcam如何无脑运行运行别人的模型(以安全帽模型为例)

maixcam如何无脑运行运行别人的模型&#xff08;以安全帽模型为例&#xff09; 本文章主要讲如何部署上传的模型文件&#xff0c;以及如果你要把你模型按照该流程应该怎么修改&#xff0c;你可以通过该文章得到你想要的应该&#xff0c;该应用也包含的退出按钮&#xff0c;是屏…

低空经济和无人机

低空经济和无人机是当前科技领域中的两个热门话题&#xff0c;它们的发展互为促进&#xff0c;共同推动着低空经济持续发热&#xff0c;投资主线也愈发清晰。 低空经济是指以低空空域为活动场所&#xff0c;以各类低空飞行器为运载工具&#xff0c;所衍生的各类经济形态、经济…

书生·浦语大模型-第七节课笔记/作业

笔记 还没看到视频 但评测对于模型优化是非常重要的&#xff0c;指引了模型选择与优化的方向 评测过程 大海捞针&#xff1a; 通过将关键信息随机插入一段长文本的不同位置&#xff0c;形成大语言模型 (LLM) 的Prompt&#xff0c;通过测试大模型是否能从长文本中提取出关键…

协议的定制之序列化与反序列化 | 守护进程

目录 一、再谈协议 二、序列化与反序列化 三、网络计算器的简单实现 四、网络计算器完整代码 五、代码改进 六、守护进程 七、Json序列化与反序列化 八、netstat 一、再谈协议 是对数据格式和计算机之间交换数据时必须遵守的规则的正式描述。简单的说了&#xff0c;网络…

FFmpeg常用实例详解

FFmpeg 是一个专业的多媒体框架&#xff0c;能够解码、编码、转码、复用、解复用、流式传输、过滤和播放几乎所有格式的媒体文件。 这里通过一些示例简单地介绍下 ffmpeg 命令的基本使用。 一、获取详细信息 ffmpeg -i <inputfile> -hide_banner 其中 -hide_banner 选项…

佛山南海区桂城珠宝玉石电商协会举办2023年度电商企业颁奖典礼

4月24日&#xff0c;佛山市南海区桂城珠宝玉石电商协会隆重举办第一届三次会员大会暨2023年度电商企业颁奖典礼&#xff0c;广邀各级政府领导、行业组织、珠宝商场、电商企业、珠宝直播达人以及新闻媒体嘉宾&#xff0c;共见璀璨&#xff0c;共话新发展、新机遇。这是平洲玉器珠…

Java-GUI-AWT-组件-TextComponent类

1 需求 2 接口 java.lang.Object java.awt.Component java.awt.TextComponent Method Detail public void setText(String t)public String getText()public String getSelectedText()public boolean isEditable()public void setEditable(boole…

docker 启动时报错

docker 启动时报如下错误 Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details 因为安装docker时添加了镜像源 解决方案&#xff1a; mv /etc/…