C++多线程学习03

news/发布时间2024/5/16 4:50:36

参考

主要参考B站up主恋恋风辰:恋恋风辰官方博客

测试加锁

#include <iostream>
#include <mutex>
#include <map>
#include <stack>
#include <shared_mutex>// 基本的加锁使用
std::mutex mtx1;void use_lock()
{int count = 10;while (count--){
#if 0mtx1.lock(); shared_data++;std::cout << "current thread is " << std::this_thread::get_id() << std::endl;std::cout << "sharad data is " << shared_data << std::endl;mtx1.unlock();
#endif// 直接使用lock_guard加锁, 程序结束自动释放std::lock_guard<std::mutex> lock(mtx1);shared_data++;std::cout << "current thread is " << std::this_thread::get_id() << std::endl;std::cout << "sharad data is " << shared_data << std::endl;std::this_thread::sleep_for(std::chrono::microseconds(10));}
}void test_lock()
{std::thread t1(use_lock);std::thread t2([]() {int count = 10;while (count--) {mtx1.lock();shared_data--;std::cout << "current thread is " << std::this_thread::get_id() << std::endl;std::cout << "sharad data is " << shared_data << std::endl;mtx1.unlock();std::this_thread::sleep_for(std::chrono::microseconds(10));}});t1.join();t2.join();
}int main()
{// 1. 测试加锁test_lock();std::cout << "Finished! \n";
}

测试线程安全数据结构1

// 保证数据安全
// 1. 错误实现
template<typename T>
class threadsafe_stack1
{
private:std::stack<T> data;mutable std::mutex m;
public:threadsafe_stack1() {}threadsafe_stack1(const threadsafe_stack1& other){std::lock_guard<std::mutex> lock(other.m);//①在构造函数的函数体(constructor body)内进行复制操作data = other.data;}threadsafe_stack1& operator=(const threadsafe_stack1&) = delete;void push(T new_value){std::lock_guard<std::mutex> lock(m);data.push(std::move(new_value));}//问题代码T pop(){std::lock_guard<std::mutex> lock(m);auto element = data.top();data.pop();return element;}bool empty() const{std::lock_guard<std::mutex> lock(m);return data.empty();}
};void test_threadsafe_stack1() {threadsafe_stack1<int> safe_stack;safe_stack.push(1);// 两个线程同时抛出,可能存在隐患,相当于pop了两次std::thread t1([&safe_stack]() {if (!safe_stack.empty()) {std::this_thread::sleep_for(std::chrono::seconds(2));safe_stack.pop();}});std::thread t2([&safe_stack]() {if (!safe_stack.empty()) {std::this_thread::sleep_for(std::chrono::seconds(2));safe_stack.pop();}});t1.join();t2.join();
}// 重新实现的线程安全栈
struct empty_stack : std::exception
{const char* what() const throw();
};template<typename T>
class threadsafe_stack
{
private:std::stack<T> data;mutable std::mutex m;
public:threadsafe_stack() {}threadsafe_stack(const threadsafe_stack& other){std::lock_guard<std::mutex> lock(other.m);//①在构造函数的函数体(constructor body)内进行复制操作data = other.data;}threadsafe_stack& operator=(const threadsafe_stack&) = delete;void push(T new_value){std::lock_guard<std::mutex> lock(m);data.push(std::move(new_value));}std::shared_ptr<T> pop(){std::lock_guard<std::mutex> lock(m);// 试图弹出前检查是否为空栈if (data.empty()) throw empty_stack();// 改动栈容器前设置返回值// 操作智能指针效率更高一些std::shared_ptr<T> const res(std::make_shared<T>(data.top()));data.pop();return res;}void pop(T& value){std::lock_guard<std::mutex> lock(m);if (data.empty()) throw empty_stack();value = data.top();data.pop();}bool empty() const{std::lock_guard<std::mutex> lock(m);return data.empty();}
};int main()
{// 2. 测试线程线程安全// test_threadsafe_stack1();std::cout << "Finished! \n";
}

死锁以及解决方案

// 关于死锁
// 加锁的顺序不对,互相占有对方的锁
// 解决方案1: 将加锁,解锁封装为独立的函数, 这样一个函数内不会使用多个锁std::mutex t_lock1;
std::mutex t_lock2;int m_1, m_2;void atomic_lock1()
{std::cout << "Lock1 begin lock" << std::endl;t_lock1.lock();m_1 = 1024;t_lock1.unlock();std::cout << "Lock1 end lock" << std::endl;
}void atomic_lock2()
{std::cout << "Lock2 begin lock" << std::endl;t_lock2.lock();m_2 = 2048;t_lock2.unlock();std::cout << "Lock2 end lock" << std::endl;
}void safe_lock1()
{int count = 10;while (count--) {atomic_lock1();atomic_lock2();std::this_thread::sleep_for(std::chrono::microseconds(5));}
}void safe_lock2()
{int count = 10;while (count--) {atomic_lock1();atomic_lock2();std::this_thread::sleep_for(std::chrono::microseconds(5));}
}void test_safe_lock()
{std::thread t1(safe_lock1);std::thread t2(safe_lock2);t1.join();t2.join();
}int main()
{// 3. 死锁// 解决方案1test_safe_lock();std::cout << "Finished! \n";
}

测试交换两个特别大的对象

// 同时加锁
class some_big_obj
{
public:some_big_obj(int data): _data(data){}// 拷贝构造some_big_obj(const some_big_obj& b) : _data(b._data){_data = b._data;}// 移动构造some_big_obj(some_big_obj&& b): _data(std::move(b._data)){}// 重载运算符friend std::ostream& operator << (std::ostream& os, const some_big_obj& big_obj){os << big_obj._data;return os;}// 重载赋值运算符some_big_obj& operator = (const some_big_obj& b){if (this == &b) return *this;_data = b._data;return *this;}// 交换数据friend void swap(some_big_obj& b1, some_big_obj& b2){some_big_obj temp = std::move(b1);b1 = std::move(b2);b2 = std::move(temp);}private:int _data;
};// 实现一个管理者class
class big_obj_manager
{
private:std::mutex      _mtx;some_big_obj    _obj;public:big_obj_manager(int data = 0): _obj(data){}void printInfo(){std::cout << "Curr obj data is " << _obj << std::endl;}friend void danger_swap(big_obj_manager& objm1, big_obj_manager& objm2);friend void safe_swap(big_obj_manager& objm1, big_obj_manager& objm2);friend void safe_swap_scope(big_obj_manager& objm1, big_obj_manager& objm2);
};// 危险的交换方式1
void danger_swap(big_obj_manager& objm1, big_obj_manager& objm2) {std::cout << "thread [ " << std::this_thread::get_id() << " ] begin" << std::endl;if (&objm1 == &objm2) {return;}std::lock_guard <std::mutex> gurad1(objm1._mtx);//此处为了故意制造死锁,我们让线程小睡一会std::this_thread::sleep_for(std::chrono::seconds(1));std::lock_guard<std::mutex> guard2(objm2._mtx);swap(objm1._obj, objm2._obj);std::cout << "thread [ " << std::this_thread::get_id() << " ] end" << std::endl;
}void test_danger_swap()
{big_obj_manager objm1(5);big_obj_manager objm2(100);std::thread t1(danger_swap, std::ref(objm1), std::ref(objm2));std::thread t2(danger_swap, std::ref(objm1), std::ref(objm2));t1.join();t2.join();objm1.printInfo();objm2.printInfo();
}// 为了避免死锁,同时对两个锁加锁
void safe_swap(big_obj_manager& objm1, big_obj_manager& objm2)
{std::cout << "thread [ " << std::this_thread::get_id() << " ] begin" << std::endl;if (&objm1 == &objm2) {return;}// 同时对两个互斥量加锁std::lock(objm1._mtx, objm2._mtx);// 使用领养锁管理自动释放std::lock_guard<std::mutex> gurad1(objm1._mtx, std::adopt_lock);// 领养后会自动释放std::this_thread::sleep_for(std::chrono::seconds(1));std::lock_guard<std::mutex> gurads(objm2._mtx, std::adopt_lock);swap(objm1._obj, objm2._obj);std::cout << "thread [ " << std::this_thread::get_id() << " ] end" << std::endl;
}void test_safe_swap()
{big_obj_manager objm1(5);big_obj_manager objm2(100);std::thread t1(safe_swap, std::ref(objm1), std::ref(objm2));std::thread t2(safe_swap, std::ref(objm2), std::ref(objm1));t1.join();t2.join();objm1.printInfo();objm2.printInfo();
}int main()
{
#if 0// 危险交换测试test_danger_swap();
#endif// 安全的交换方式test_safe_swap();std::cout << "Finished! \n";
}

层级锁避免死锁

// 实际开发中,锁的顺序可能很难注意,可以使用层级锁避免死锁
class hierarchical_mutex
{
private:std::mutex              _internal_mutex;unsigned long const     _hierarchy_value;            // 当前层级值unsigned long           _previous_hierarchy_value;   // 上一层级值static thread_local unsigned long _this_thread_hierarchy_value;     // 记录本线程层级值void check_for_hierarchy_violation(){if (_this_thread_hierarchy_value <= _hierarchy_value){throw std::logic_error("mutex hierarchy violated");}}void update_hierachy_value(){_previous_hierarchy_value = _this_thread_hierarchy_value;_this_thread_hierarchy_value = _hierarchy_value;}public:explicit hierarchical_mutex(unsigned long value): _hierarchy_value(value), _previous_hierarchy_value(0){}hierarchical_mutex(const hierarchical_mutex&) = delete;hierarchical_mutex& operator=(const hierarchical_mutex&) = delete;void lock(){check_for_hierarchy_violation();_internal_mutex.lock();update_hierachy_value();}void unlock(){if (_this_thread_hierarchy_value != _hierarchy_value)throw std::logic_error("mutex hierachy violated");_this_thread_hierarchy_value = _previous_hierarchy_value;_internal_mutex.unlock();}bool try_lock(){check_for_hierarchy_violation();if (!_internal_mutex.try_lock()) {return false;}update_hierachy_value();return false;}
};// 初始化静态变量
thread_local unsigned long hierarchical_mutex::_this_thread_hierarchy_value(ULONG_MAX);// 测试层级锁
void test_hierarchy_lock()
{hierarchical_mutex      hmtx1(1000);hierarchical_mutex      hmtx2(500);std::thread t1([&hmtx1, &hmtx2]() {hmtx1.lock();hmtx2.lock();hmtx2.unlock();hmtx1.unlock();});#if 0// 以下是错误代码std::thread t2([&hmtx1, &hmtx2]() {hmtx2.lock();hmtx1.lock();hmtx1.unlock();hmtx2.unlock();});
#endift1.join();// t2.join();
}int main()
{// 4. 实现一个层级锁test_hierarchy_lock();std::cout << "Finished! \n";
}

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

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

相关文章

在CentOS上使用Docker搭建Halo博客并实现远程访问的详细指南

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. Docker部署Halo1.1 检查Docker版本1.2 在Docker中部署Halo 二. Linux安装Cpol…

2024全国水科技大会暨减污降碳协同增效创新与实践论坛(八)

召集人&#xff1a;王洪臣 中国人民大学环境学院教授 姚 宏 北京交通大学教授 为大会征集“绿色低碳污水厂案例”&#xff0c;欢迎各相关单位积极报名&#xff01; 一、会议背景 生态环境部、国家发展和改革委员会等七部门印发《减 污降碳协同增效实施方案》中明确提出推进水…

python Matplotlib Tkinter-->tab切换1

环境 python:python-3.12.0-amd64 包: matplotlib 3.8.2 pillow 10.1.0 import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import tkinter as tk import tkinter.messagebox as messagebox import …

google浏览器chrome无法访问localhost等本地虚拟域名的解决方法

场景一&#xff1a; 谷歌浏览器访问出现&#xff1a;forbbiden 403 问题&#xff0c;或者直接跳转到正式域名(非本地虚拟域名) 访问本地的虚拟域名http://www.hd.com/phpinfo.php?p1发生了302 条状 火狐浏览器正常访问; 解决方法&#xff1a; 方法1&#xff1a;在谷歌浏览器…

CPU处理器NUMA架构简介

在实际工作中&#xff0c;经常遇到服务器是否开启NUMA、NUMA绑定几颗Core、跨NUMA节点访问的性能下降等等话题。那么NUMA作为非一致性内存访问的多处理器架构&#xff0c;在架构上有什么特性、与SMP架构有哪些不同&#xff0c;调优策略等&#xff0c;本文将作简要介绍。 1、CPU…

Linux/Spectra

Enumeration nmap 第一次扫描发现系统对外开放了22&#xff0c;80和3306端口&#xff0c;端口详细信息如下 22端口运行着ssh&#xff0c;80端口还是http&#xff0c;不过不同的是打开了mysql的3306端口 TCP/80 进入首页&#xff0c;点击链接时&#xff0c;提示域名不能解析&…

测试:腾讯云4核8G服务器支持多少人在线访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

【MySQL】SQL 优化

MySQL - SQL 优化 1. 在 MySQL 中&#xff0c;如何定位慢查询&#xff1f; 1.1 发现慢查询 现象&#xff1a;页面加载过慢、接口压力测试响应时间过长&#xff08;超过 1s&#xff09; 可能出现慢查询的场景&#xff1a; 聚合查询多表查询表数据过大查询深度分页查询 1.2 通…

【SVN】使用TortoiseGit删除Git分支

使用TortoiseGit删除Git分支 前言 平时我在进行开发的时候&#xff0c;比如需要开发一个新功能&#xff0c;这里以蘑菇博客开发服务网关-gateway功能为例 一般我都会在原来master分支的基础上&#xff0c;然后拉取一个新的分支【gateway】&#xff0c;然后在 gateway分支上进…

git忽略某些文件(夹)更改方法

概述 在项目中&#xff0c;常有需要忽略的文件、文件夹提交到代码仓库中&#xff0c;在此做个笔录。 一、在项目根目录内新建文本文件&#xff0c;并重命名为.gitignore&#xff0c;该文件语法如下 # 以#开始的行&#xff0c;被视为注释. # 忽略掉所有文件名是 a.txt的文件.…

Prompt 编程的优化技巧

一、为什么要优化 一&#xff09;上下文限制 目前 GPT-3.5 以及 GPT-4最大支持 16K 上下文&#xff0c;比如你输入超过 16k 的长文本&#xff0c;ChatGPT 会提示文本过大&#xff0c;为了避免 GPT 无法回复&#xff0c;需要限制 上下文在16k 以内 上下文对于 GPT 来说是非常重…

如何选择科技公司或者技术团队来开发软件项目呢

最近有客户问我们为什么同样软件项目不同公司报价和工期差异很大&#xff0c;我们给他解释好久才讲清楚&#xff0c;今天整理一下打算写一篇文章来总结一下&#xff0c;有需要开发朋友可以参考&#xff0c;我们下次遇到客户也可以直接转发文章给客户自己看。 我们根据我们自己报…

AllSky - 220 Sky Skybox Set

适于Unity的220多个天空! - 各种风格:白天、夜晚、动漫、云上、卡通、幻想、朦胧、壮丽、太空、 乳状云、无阳光和无月光! - 适用于寻找各种各样的天空以照亮其环境的照明艺术家、环境艺术家和独立开发人员。 - 从白天到夜晚的照明:黄昏、日落、白天的多个时间段、夜晚的多…

matlab 三质量-弹簧系统受激振力

1、内容简介 略 44-可以交流、咨询、答疑 建立系统运动方程&#xff0c;研究固有频率和对应主振型 2、内容说明 略 三质量&#xff0d;弹簧系统受激振力&#xff0c;并不考虑各自的阻尼。建立系统运动方程。 解&#xff1a;由于阻尼对固有频率没有影响&#xff0c;故本文不…

pclpy 最小二乘法拟合平面

pclpy 最小二乘法拟合平面 一、算法原理二、代码三、结果1.左边原点云、右边最小二乘法拟合平面后点云投影 四、相关数据 一、算法原理 平面方程的一般表达式为&#xff1a; A x B y C z D 0 ( C ≠ 0 ) Ax By Cz D 0 \quad (C\neq0) AxByCzD0(C0) 即&#xff1a; …

搭建Facebook直播网络对IP有要求吗?

在当今数字化时代&#xff0c;Facebook直播已经成为了一种极具吸引力的社交形式&#xff0c;为个人和企业提供了与观众直接互动的机会&#xff0c;成为推广产品、分享经验、建立品牌形象的重要途径。然而&#xff0c;对于许多人来说&#xff0c;搭建一个稳定、高质量的Facebook…

第十二章 Linux——日志管理

第十二章 Linux——日志管理 基本介绍系统常用日志日志管理服务日志轮替基本介绍日志轮替文件命名logrotate配置文件自定义加入日志轮转应用实例 日志轮替机制原理查看内存日志 基本介绍 日志文件是重要的系统信息文件&#xff0c;其中记录了许多重要的系统事件&#xff0c;包…

基础算法(二)( 枚举)

1.枚举算法介绍&#xff1a; 枚举算法是一种基本的算法思想&#xff0c;它通过穷举所有可能的情况来解决问题。它的基本思想是将问题的解空间中的每个可能的解都枚举出来&#xff0c;并进行验证和比较&#xff0c;找到满足问题条件的最优解或者所有解。枚举算法适用于问题规模…

阿里云文件验证方式申请SSL证书的教程

文件验证方式申请SSL免费证书 ***.com.cn 下载验证文件然后解压出来 将验证文件放到通过域名的80端口能访问到的地方&#xff1a;E:\deploy\dygw.well-known\pki-validation 验证文件返回的内容

C++ 学习之函数对象

C 函数对象基本概念 在C中&#xff0c;函数对象&#xff08;Function Objects&#xff09;是一种类或结构体&#xff0c;它重载了函数调用运算符operator()&#xff0c;因此可以像函数一样被调用。函数对象有时也被称为仿函数&#xff08;Functor&#xff09;。 以下是关于C函…
推荐文章