并发支持库(3)-互斥

互斥可以对操作集合上锁,避免多个线程同时访问共享资源。这些操作集合可以看作是一次原子操作。

本文章的代码库:

https://gitee.com/gamestorm577/CppStd

1. 互斥类

c++提供了各种互斥类。

mutex

构造函数

默认构造函数构造一个处于未锁定状态的互斥

锁定

mutex提供lock和try_lock接口用于锁定互斥,unlock用于解锁互斥。

1.调用线程调用lock时,如果mutex为未锁定状态,那么调用线程锁住该互斥;如果mutex为锁定状态,那么调用线程阻塞,知道mutex被解锁。

2.调用线程调用try_lock尝试锁定mutex并立即返回。如果mutex为未锁定状态,那么try_lock返回true并锁住mutex;如果mutex为锁定状态,try_lock返回false。

3.调用线程调用unlock解锁互斥。

4.调用线程调用lock或者try_lock时必须不占有mutex,调用unlock时mutex必须被调用线程锁定,否则会出现未定义行为。

代码示例:

int num = 0;
std::mutex mutex;auto Func = [&](int id)
{for (int i = 0; i < 5; ++i){mutex.lock();++num;std::cout << id << ": " << num << std::endl;mutex.unlock();std::this_thread::sleep_for(std::chrono::milliseconds(100));}
};std::thread t1(Func, 0);
std::thread t2(Func, 1);
t1.join();
t2.join();

可能的输出结果:

0: 1
1: 2
0: 3
1: 4
0: 5
1: 6
0: 7
1: 8
1: 9
0: 10

native_handle

返回mutex的底层实现句柄

timed_mutex

相比mutex,timed_mutex可以实现指定时间的锁定,对应的接口为try_lock_for和try_lock_until。

recursive_mutex

对于mutex,当某个执行线程已经占用mutex的情况下不能再调用lock或者try_lock,而recursive_mutex可以去掉这个限制。注意在占用mutex的情况下,调用recursive_mutex的lock或者try_lock也是有次数限制的。

recursive_time_mutex

和recursive_mutex的功能相同,同时增加了指定时间的锁定功能。

shared_mutex

shared_mutex有两个访问级别:共享性和独占性。如果一个执行线程获取了shared_mutex的独占行,那么其他线程无法获取该锁。当没有任何线程获取shared_mutex的独占性时,多个线程可以同时获取shared_mutex的共享性。

对于一些共享资源读取远多于写入操作的场景,shared_mutex可以提高并发性能。

shared_mutex的lock、try_lock接口用于获取独占性,unlock用于解锁独占性。lock_shared、try_lock_shared接口口用于获取共享性,unlock_shared用于解锁共享性。

代码示例:

auto Timer = [](std::function<void()> func) -> void
{auto start = std::chrono::system_clock::now();func();auto end = std::chrono::system_clock::now();std::chrono::duration<double, std::milli> time = end - start;std::cout << "use time: " << time.count() << std::endl;
};struct Test1
{void Func(){m_Mut.lock();std::this_thread::sleep_for(std::chrono::milliseconds(10));m_Mut.unlock();}std::mutex m_Mut;
};struct Test2
{void Func(){m_Mut.lock_shared();std::this_thread::sleep_for(std::chrono::milliseconds(10));m_Mut.unlock_shared();}std::shared_mutex m_Mut;
};auto Func1 = []()
{Test1 test1;std::vector<std::thread> threads(20);for (auto& t : threads){t = std::thread(&Test1::Func, &test1);}for (auto& t : threads){t.join();}
};auto Func2 = []()
{Test2 test2;std::vector<std::thread> threads(20);for (auto& t : threads){t = std::thread(&Test2::Func, &test2);}for (auto& t : threads){t.join();}
};Timer(Func1);
Timer(Func2);

输出结果:

use time: 326
use time: 33.2421

shared_timed_mutex

shared_timed_mutex和shared_mutex的功能相同,并且支持指定时间的锁定

2. lock类

c++提供了一些lock类用于方便地管理互斥类

lock_guard

lock_guard提供互斥体的RAII风格的包装。当创建lock_guard对象时,它试图占有给定互斥的所有权,当lock_guard离开作用域时,lock_guard被销毁并释放互斥体。代码示例:

struct MyMutex
{void lock(){std::cout << "MyMutex lock" << std::endl;}void unlock(){std::cout << "MyMutex unlock" << std::endl;}
};MyMutex mut;
std::lock_guard<MyMutex> lock(mut);

输出结果:

MyMutex lock
MyMutex unlock

scoped_lock

scoped_guard提供多个互斥体的RAII风格的包装。代码示例:

struct MyMutex
{void lock(){std::cout << "MyMutex lock: " << Id << std::endl;}bool try_lock(){std::cout << "MyMutex try_lock: " << Id << std::endl;return true;}void unlock(){std::cout << "MyMutex unlock: " << Id << std::endl;}int Id = 0;
};MyMutex mut1;
MyMutex mut2;
MyMutex mut3;
mut1.Id = 3;
mut2.Id = 17;
mut3.Id = 29;std::scoped_lock lock(mut1, mut2, mut3);

输出结果:

MyMutex lock: 3
MyMutex try_lock: 17
MyMutex try_lock: 29
MyMutex unlock: 3
MyMutex unlock: 17
MyMutex unlock: 29

unique_lock

unique_lock是一个通用的互斥包装器。

shared_lock

shared_lock是一个通用的共享互斥包装器。

3. 通用锁定算法

c++提供了std::try_lock、std::lock用于锁定互斥

4. 单次调用

c++提供了接口std::call_once来确保函数只被调用一次,无论是单线程还是多线程。代码示例:

struct Test
{void Func(){std::cout << "call Func: " << Id << std::endl;}void CallFuncOnce(){std::call_once(flag, &Test::Func, this);}std::once_flag flag;int Id = 0;
};Test test1;
Test test2;
test1.Id = 3;
test2.Id = 17;test1.CallFuncOnce();
test1.CallFuncOnce();
test1.CallFuncOnce();
test1.CallFuncOnce();std::jthread t1(&Test::CallFuncOnce, &test2);
std::jthread t2(&Test::CallFuncOnce, &test2);
std::jthread t3(&Test::CallFuncOnce, &test2);

输出结果:

call Func: 3
call Func: 17

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

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

相关文章

短路逻辑运算--c语言

#include<stdio.h>int main() { int i1; i,i||i; printf("%d",i);//3return 0; } 再逻辑运算的原则一定优先于其他逻辑判断&#xff0c;再这个式子中||前面的结果已经为真存在逻辑短路的情况所以不用管后面的式子。 i&#xff0c;i自增两次i3&#xff0c;

爬虫技术之正则提取静态页面数据

第一天 简单示例 在爬虫过程中&#xff0c;我们获取到了页面之后&#xff0c;通常需要做的就是解析数据&#xff0c;将数据持久化到数据库为我所用。如何又快又准确得提取有效数据&#xff1f;这是一门技术&#xff0c;看了我的博客之前可能略有难度&#xff0c;但各位大师看…

redis源码分析

是什么 是基于内存(而不是磁盘)的kv(而不是关系型mysql那种)数据库&#xff0c;通过空间换时间 源码分析 跳表skiplist 假设你有个有序链表&#xff0c;你想看某个特定的值是否出现在这个链表中&#xff0c;那你是不是只能遍历一次链表才能知道&#xff0c;时间复杂度为O(n…

Postman环境变量全局变量设置(详解版)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 在公司中&#xff0c;一般会存在开发环境、测试环境、线上环境等…

找不到mfc140u.dll怎么办?修复缺失mfc140u.dll的多种方案分享

mfc140u.dll文件是一个重要的动态链接库文件&#xff0c;它在Windows操作系统中发挥着关键的作用。由于各种原因&#xff0c;例如应用程序冲突或系统错误等&#xff0c;mfc140u.dll文件有时会出现丢失的情况。一旦发生这种问题&#xff0c;运行依赖此文件的应用程序将无法正常启…

力扣刷题日记——L724. 寻找数组的中心下标

1. 前言 今天是力扣刷题日记的第二天&#xff0c;今天依旧是一道简单题啊&#xff0c;慢慢来&#xff0c;先看看题目是什么吧。 2. 题目描述 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和…

JSP中间件漏洞

jsp的注入最难挖 另外3个好挖 struts2 url有action 就代表是struts2 用漏洞利用工具 下面之这两个一般都可以用工具扫一下 、 有些网站看起来没有 action实际上我们提交了 我们的账号和密码 之后就有了 工具包是下面 这些 github上面也有 用法就是如下图 把url放进去就…

数据库驱动和url连接示例

1.MySQL 配置示例&#xff1a;↓ driver_class:com.mysql.cj.jdbc.Driver url:jdbc:mysql://IP地址:端口号/数据库名?characterEncodingUTF-8&useSSLfalse&useUnicodetrue&serverTimezoneUTC 2.MySQL(使用information_schema查询表结构) 配置示例&#xff1a;↓…

关于数据预处理的重要性

主要是为了计算机能够准确的理解数据 以下是需要处理的数据&#xff1a; 1、缺失值 仅一部分实例有值的特性&#xff0c;以及没有任何特征值的实例都被视为缺失数据 一个特征丢失了超过5%~10%的值&#xff0c;被认为是缺失数据 缺失值实例应该被删除&#xff0c;避免引入偏…

【ST-学习链接】

ST-学习链接 ■ 江科大STM32学习笔记&#xff08;上下&#xff09;■ STM32 学习&#xff08;四&#xff09;中断系统 ■ 江科大STM32学习笔记&#xff08;上下&#xff09; 江科大STM32学习笔记&#xff08;上&#xff09; 江科大STM32学习笔记&#xff08;下 ■ STM32 学习…

整数和浮点数在内存中储存的形式

整数 整数的二进制表示法有三种&#xff0c;即原码、反码、补码。 三种表示方式均有符号位和数值位 符号位位于数值位最高位的那一位&#xff0c;分别用0和1表示&#xff0c;0表示正数&#xff0c;1表示负数。 数值位&#xff0c;除最高位的那一位外其他都是数值位。 正整数…

续篇:展开聊下 state 与 渲染树中位置的关系

&#x1f43e; 上篇的结尾处&#xff0c;提到了 > 为了提升性能&#xff0c; React 仅在渲染之间 存在差异 时才会更改 DOM 节点。 本篇&#xff0c;✓ &#x1f1e8;&#x1f1f3; 展开聊下 state 与 渲染树中位置的关系 &#x1f4e2;&#x1f4e2;&#x1f4e2; 状态与…

PAT 2024年春季(乙级)

补题链接&#xff1a;PAT 2024春&#xff08;乙级&#xff09; B-1 合成 2024 给定n和m&#xff0c;让我们判断能不能由n个不同的偶数和m个不同的奇数组成2024。 正难则反&#xff0c;我们考虑什么情况下不能组成2024。 先从奇偶性判断&#xff0c;n个偶数一定是偶数&#…

每日OJ题_哈希表②_力扣面试题 01.02. 判定是否互为字符重排

目录 力扣面试题 01.02. 判定是否互为字符重排 解析代码 力扣面试题 01.02. 判定是否互为字符重排 面试题 01.02. 判定是否互为字符重排 难度 简单 给定两个由小写字母组成的字符串 s1 和 s2&#xff0c;请编写一个程序&#xff0c;确定其中一个字符串的字符重新排列后&am…

量化交易平台之一:PyAlgoTrade

一、前言 PyAlgoTrade是一个Python的算法交易库&#xff0c;支持策略回测和实时交易&#xff0c;提供了丰富的统计和分析功能。github地址&#xff1a;GitHub - gbeced/pyalgotrade: Python Algorithmic Trading Library 二、使用 PyAlgoTrade是一个功能强大的Python量化交易平…

GIS瓦片3-WMTS瓦片

介绍 WMTS( Web Map Tile Service)切片地图Web服务&#xff08;OpenGIS Web Map Tile Service&#xff09;当前最新版本是1.0.0。WMTS标准定义了一些操作&#xff0c;这些操作允许用户访问切片地图。WMTS可能是OGC首个支持RESTful访问的服务标准。 WMTS提供了一种采用预定义图…

c# 数组的使用

一、简述 您可以在数组数据结构中存储相同类型的多个变量。您可以通过指定数组元素的类型来声明数组。如果您希望数组存储任何类型的元素&#xff0c;您可以指定object其类型。在 C# 的统一类型系统中&#xff0c;所有类型&#xff08;预定义的和用户定义的、引用类型和值类型&…

docker搭建odoo16开发环境

要使用Docker搭建Odoo 16的开发环境&#xff0c;我们需要准备两个主要文件&#xff1a;一个是docker-compose.yml文件&#xff0c;用来定义和运行多个Docker应用容器&#xff0c;包括Odoo 16和PostgreSQL 15&#xff1b;另一个是odoo.conf文件&#xff0c;用来配置Odoo应用。下…

Vue2利用创建a标签实现下载本地静态文件到本地电脑上的功能

最近PC项目遇到一个需求&#xff0c;那就是需要前端下载前端代码包里的前端文件到本地&#xff0c;并且可以给下载下来的文件名指定任意的文件名&#xff0c;如下图所示&#xff0c;在前端代码里public里的statics里有个静态文件zswj.pem&#xff0c;页面上有个下载按钮&#x…

CPU设计实战-协处理器访问指令的实现

目录 一 协处理器的作用与功能 1.计数寄存器和比较寄存器 2.Status寄存器 3.Cause寄存器(标号为13) 4.EPC寄存器(标号为14) 5.PRId寄存器(标号为15) 6.Config 寄存器(标号为16)-配置寄存器 二 协处理器的实现 三 协处理器访问指令说明 四 具体实现 1.译码阶段 2.执行…