【C++】详解std::mutex

news2025/1/10 16:07:39

2023年9月11日,周一中午开始

2023年9月11日,周一晚上23:25写完


目录

  • 概述
  • 头文件
  • std::mutex类的成员
  • 类型
  • 方法
  • 没有std::mutex会产生什么问题
  • 问题一:数据竞争
  • 问题二:不一致
  • lock和unlock
  • 死锁

概述

std::mutex是C++标准库中提供的一种同步原语,用于保护共享资源的访问

std::mutex通过锁定互斥锁来实现对共享资源的保护。当一个线程获取了互斥锁后,其他线程必须等待该互斥锁被释放才能继续访问共享资源。这样可以确保在同一时刻只有一个线程能够访问共享资源,从而避免了多个线程同时访问同一资源而导致的数据竞争不一致问题。

头文件

#include<mutex>

std::mutex类的成员

类型

native_handle_type    原生的互斥锁句柄类型

方法

(constructor)    构造互斥锁(公共函数)

lock    锁上互斥锁(公共函数)

try_lock    如果互斥锁没锁上就锁上互斥锁(公共函数)

unlock    解除互斥锁(公共函数)

native_handle    获取原生的互斥锁句柄(公共函数)

没有std::mutex会产生什么问题

问题一:数据竞争

在这个程序中,共享资源是count,count的值为0

按理来说,一个线程给count增加100000,另一个线程给count减去100000,最后的count应该还是0,但是事实上却不是这样,这就是数据竞争所造成的。

#include <iostream>
#include <mutex>
#include <thread>

int count = 0;

void thread1() {
  for(int i = 0; i < 100000; i++) {
  count++; 
  }
}

void thread2() {
  for(int i = 0; i < 100000; i++) {  
  count--;
  }
}

int main() {
  std::thread t1(thread1);
  std::thread t2(thread2);

  t1.join();
  t2.join();

  std::cout <<"count:"<< count << std::endl; // 可能打印非0值
}

问题二:不一致

多个线程对共享数据进行操作,由于缓存一致性问题,可能导致其中一个线程看到的数据不是最新值。

比如在这个程序里面,有时候判断x==1是true,有时候判断x==1是false

#include <iostream>
#include <mutex>
#include <thread>

int x = 0;

void thread1() {
  x = 1; 
}

void thread2() {
  if(x == 1)
	std::cout << "x is 1" << std::endl; 
  else
	std::cout << "x is not 1" << std::endl; 
}

int main() {
  std::thread t1(thread1);
  std::thread t2(thread2);

  t1.join();
  t2.join();

}

lock和unlock

通过lock/unlock可以保证任何时刻只有一个线程在访问共享资源,从而避免数据竞争问题。

#include <iostream>
#include <mutex>
#include <thread>

std::mutex mutex;
int count = 0;

void thread1() {
  for(int i = 0; i < 100000; i++) {
	  // 锁定互斥锁
	  mutex.lock();  
	  
	  count++; 
	  
	  // 解锁互斥锁
	  mutex.unlock();
  }
}

void thread2() {
  for(int i = 0; i < 100000; i++) {  
	  // 锁定互斥锁
	  mutex.lock();  
	  
	   count--;
	   
	  // 解锁互斥锁
	  mutex.unlock();
  }
}

int main() {
  std::thread t1(thread1);
  std::thread t2(thread2);

  t1.join();
  t2.join();

  std::cout <<"count:"<< count << std::endl; 
}

可以看到数据竞争的问题得到了解决

死锁

死锁(Deadlock)是多线程或多进程编程中的一个严重问题,它会导致程序无法继续执行下去,因为一组线程或进程相互等待对方释放资源,但永远无法满足条件,从而陷入僵局。

死锁的定义是:多个线程因为抢占和持有资源而造成的一种互相等待的僵局状态

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mutex1;
std::mutex mutex2;

void threadA() {
    std::cout << "Thread A: Attempting to lock mutex1..." << std::endl;
    mutex1.lock();
    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    std::cout << "Thread A: Attempting to lock mutex2..." << std::endl;
    mutex2.lock();
    
    // 执行任务...
    
    mutex2.unlock();
    mutex1.unlock();
}

void threadB() {
    std::cout << "Thread B: Attempting to lock mutex2..." << std::endl;
    mutex2.lock();
    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    std::cout << "Thread B: Attempting to lock mutex1..." << std::endl;
    mutex1.lock();
    
    // 执行任务...
    
    mutex1.unlock();
    mutex2.unlock();
}

int main() {
    std::thread t1(threadA);
    std::thread t2(threadB);

    t1.join();
    t2.join();

    return 0;
}

可以看到程序一直卡住

为什么会卡住呢?

  1. 线程A首先尝试锁定mutex1,并成功获得锁。

  2. 线程B首先尝试锁定mutex2,并成功获得锁。

  3. 接下来,线程A想要锁定mutex2,但它被线程B持有,因此线程A被阻塞,无法继续执行,等待mutex2被释放。

  4. 同样地,线程B想要锁定mutex1,但它被线程A持有,因此线程B也被阻塞,等待mutex1被释放。

现在,线程A和线程B都被阻塞,它们相互等待对方释放资源,但又不会主动释放自己的锁。这就是典型的死锁情况:两个或多个线程互相等待对方释放资源,导致程序无法继续执行下去。

根本原因在于线程拿不到锁时就会被阻塞。

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

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

相关文章

2024苹果手机软件备份软件工具iMazing

很多人都会忘记备份iOS 资料&#xff0c;或者因为设置备份时间、位置等不到位&#xff0c;导致需要用的时候找不到备份。接下来&#xff0c;小编就来教大家iMazing软件备份功能的几个设置小技巧&#xff0c;都在软件界面的“选项”内调整&#xff0c;减少备份过程中的出错。 图…

【Electron】electron与cljs的处理

实现效果: 前言&#xff1a; 如何用cljs的方式&#xff0c;编写electron应用&#xff0c;可以实现多窗体应用 要使用ClojureScript&#xff08;CLJS&#xff09;编写一个 Electron 应用程序&#xff0c;并实现多窗体功能&#xff0c;您可以按照以下步骤进行操作&#xff1a; …

管易云与金蝶云星空对接集成仓库查询打通仓库新增

管易云与金蝶云星空对接集成仓库查询打通仓库新增 接通系统&#xff1a;管易云 管易云是金蝶旗下专注提供电商企业管理软件服务的子品牌&#xff0c;先后开发了C-ERP、EC-OMS、EC-WMS、E店管家、BBC、B2B、B2C商城网站建设等产品和服务&#xff0c;涵盖电商业务全流程。 对接目…

KEIL5工程改名3步骤

实际上无法另存&#xff0c;通过复制改名方式来间接完成。 如下3个步骤可以完成改名 &#xff08;1&#xff09;直接修改FX3U_STM32F407.uvprojx 文件名称&#xff0c;体现在左上角第一行&#xff0c;Project&#xff1a;xxxx &#xff08;2&#xff09;点开工程option&#…

SEO和SEM的区别与联系:优化和推广的艺术

SEO和SEM的区别与联系&#xff1a;优化和推广的艺术 在当今商业竞争日益激烈的市场环境下&#xff0c;企业对于网站的建设和管理越来越重视。为了吸引更多的潜在客户&#xff0c;企业不得不花费大量时间和资源来进行SEO优化和SEM推广。虽然二者都是提高网站流量的有效方法&…

如何像 Sealos 一样在浏览器中打造一个 Kubernetes 终端?

作者&#xff1a;槐佳辉。Sealos maintainer 在 Kubernetes 的世界中&#xff0c;命令行工具&#xff08;如 kubectl 和 helm&#xff09;是我们与集群交互的主要方式。然而&#xff0c;有时候&#xff0c;我们可能希望能够在 Web 页面中直接打开一个终端&#xff0c;执行这些命…

【前端项目】博客系统(页面设计)

文章目录 一、预期效果二、实现博客列表页三、实现博客正文页四、实现博客登录页五、实现博客编辑页 一、预期效果 代码详情见&#xff1a;gitee链接 &#x1f495; 博客列表页效果 &#x1f495; 博客详情页效果 &#x1f495; 博客登录页效果 &#x1f495; 博客编辑页效果…

2招教你解决:iPhone微信黑名单怎么恢复好友

前几天和男朋友吵架了&#xff0c;一气之下就把他拉黑了。现在想把他恢复回来&#xff0c;但是一直找不到他的聊天对话框&#xff0c;所以想问问大家该怎么将他移出黑名单。 无论是情侣吵架、朋友吵架还是与家人之间有矛盾&#xff0c;大家很容易在怒火的刺激下将对方拉入黑名单…

通过阿贝云免费云服务器部署vue3+vite项目

通过阿贝云免费云服务器部署vue3vite项目 阿贝云&#xff1a;https://www.abeiyun.com 首先访问阿贝云登录后申请服务器&#xff0c;需要关注微信公众号绑定 然后我们给服务器安装操作系统&#xff0c;这里我使用了centos7.6 这里我使用finalshell 连接服务器 我们首先配置ng…

apple pencil的替代品买啥比较好?平价电容笔排行榜

电容笔作为现在当下热销的数码配件&#xff0c;国内许多品牌商也加入其中&#xff0c;导致许多小伙伴购选的难度加大&#xff0c;太多品牌&#xff0c;看得眼花缭乱&#xff0c;更不知道哪些功能比较好&#xff0c;要想在这么多品牌中找到适合自己的&#xff0c;更是难上加难。…

2024年java面试--mysql(3)

系列文章目录 2024年java面试&#xff08;一&#xff09;–spring篇2024年java面试&#xff08;二&#xff09;–spring篇2024年java面试&#xff08;三&#xff09;–spring篇2024年java面试&#xff08;四&#xff09;–spring篇2024年java面试–集合篇2024年java面试–redi…

【前端开发】JS Vue React中的通用递归函数

文章目录 前言一、递归函数的由来二、功能实现1.后台数据2.处理数据3.整体代码 总结 前言 大家好&#xff0c;今天和大家分享一下在前端开发中js&#xff0c;vue&#xff0c;react的通用递归方法。 递归是指一个函数在执行过程中调用自身的行为。通过递归&#xff0c;可以将一…

SpringBoot 基于 MongoTemplate 的工具类

一、 什么是MongoDB MongoDB基于分布式文件存储的数据库。由C语言编写。MongoDB是一个高性能&#xff0c;开源&#xff0c;无模式的文档型数据库&#xff0c;是当前NoSql数据库中比较热门的一种。 他支持的数据结构非常松散&#xff0c;是类似json的bjson格式&#xff0c;因此…

SAP GUI 8.0 SMARTFORMS 使用SCR LEGACY TEXT EDITOR GUI8.00 禁用MSWORD

Smartforms使用WORD作为编辑器是很痛苦的一个事情&#xff0c;不支持拖拽&#xff0c;还很慢&#xff0c;各种不习惯&#xff0c;总之是非常的不舒服&#xff0c;能导致失眠。 在S/4以前的系统&#xff0c;可以使用TCODE I18N或者程序RSCPSETEDITOR或者暴力党直接改表TCP0I来…

SAP-ABAP-底表的创建和应用-01

1、创建底表SE11 给底表起个名字&#xff0c;点击创建 输入描述&#xff0c;选择交付类A&#xff0c;表视图维护选择&#xff1a;X允许显示维护。如果选择N&#xff0c;就不能维护数据了。 点击字段页签,维护字段 维护完自己需要的字段&#xff0c;点击激活&#xff0c;或触发…

Oracle(1):Oracle简介

1 什么是 ORACLE ORACLE 数据库系统是美国 ORACLE 公司&#xff08;甲骨文&#xff09;提供的以分布式数据库为核心的一组软件产品&#xff0c;是目前最流行的客户/服务器(CLIENT/SERVER)或B/S 体系结构的数据库之一。 ORACLE 通常应用于大型系统的数据库产品。 ORACLE 数据…

Java基于SpringBoot+Vue的 4S店车辆管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 功能总览4 系统设计4.1 系统设计主要功能4.2 数据库设计4.2.1 数据库设计规范4.2…

Numba:加速python代码

通常我们加速python代码是考虑把.py文件编译成.c文件&#xff0c;然后把.c文件编译成.so或.pyd文件&#xff0c;可以参考另一章博文&#xff1a; Cython为py程序加密&提高性能_cythonize_Rnan-prince的博客-CSDN博客 现在我们考虑一种不用将py文件编译成.c文件的方法&…

正中优配:月线macd指标参数设置?

随着投资者长期持有股票的越来越受欢迎&#xff0c;月线MACD目标已成为识别趋势和交易信号的重要东西。但是&#xff0c;许多投资者在设置MACD目标参数时仍然感到困惑。本文将从多个视点剖析&#xff0c;为您解答月线MACD目标参数设置的问题。 什么是MACD目标&#xff1f; MAC…

630. 课程表 III

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;贪心优先队列 写在最后 Tag 【贪心】【优先队列】【数组】 题目来源 630. 课程表 III 题目解读 有 n 门编号从 1 到 n 的课程&#xff0c;有一个数组 courses&#xff0c;其中 courses[i] [duration, lastDay] 表示…