C++并发编程2——为共享数据加锁(四)

C++并发编程 线程间的数据共享 1. 为什么要并发?分离关注点、提升性能 2. 何时不用并发?收益比不上成本。 启动线程存在固有开销 线程需要独立的堆栈空间 运行线程时,操作系统每次上下文切换都需要耗费时间 3. C++11支持的并发:全新的线程感知内存模型,以及管理线程、保护共享数据、线程同步和原子操作等 4. 线程:启动线程 、等待线程结束join() 或自主运行detached() (当线程退出时, 相关资源的能够正确回收) 5. 线程间共享数据 条件竞争(race condition):不变量遭到破坏(比如双向... 阅读详情

如果某个想法是你唯一的想法,再也没有比这个更危险的事情了。

本节会阐述保护共享数据的替代方案,很多情况下,使用互斥量并不合适,会带来性能消耗。下文会详细讲解集中通用的场景。

保护共享数据的初始化过程

为了防止共享数据初始化时数据被破坏,C++提供了std::once_flag和std::call_once来保证共享数据初始化的正确性。

// using mutex
std::shared_ptr<some_resource> resource_ptr;
std::mutex resource_mutex;
void foo() 
{
    std::unique_lock<std::mutex> lk(resource_mutex);
    if(!resource_ptr)
    {
        resource_ptr.reset(new some_resource);
    }
    lk.unlock();
    resource_ptr->do_something();
}

// using call_once
std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;

void int_resource()
{
    resource_ptr.reset(new some_resource);
}

void foo()
{
    std::call_once(resource_flag, init_resource);
    resource_ptr->do_something();
}

保护很少更新的数据量

对于这种共享数据可以采用“读者-写着锁”,其允许两种不同的使用方式:一个作者线程独占访问和共享访问,让多个读者线程并发访问。

C++标准并没有提供相关的解决方案,我们可以使用boost::shared_mutex来做同步。对于更新操作,可以使
用std::lock_guard<boost::shared_mutex>和std::unique_lock<boost::shared_mutex>进行上锁;对于访问操作,可以使用boost::shared_lock<boost::shared_mutex>获取共享访问权。我们来看下面例子:

#include <map>
#include <string>
#include <mutex>
#include <boost/thread/shared_mutex.hpp>
class dns_entry;
class dns_cache
{
  std::map<std::string,dns_entry> entries;
  mutable boost::shared_mutex entry_mutex;
public:
  dns_entry find_entry(std::string const& domain) const
  {
    boost::shared_lock<boost::shared_mutex> lk(entry_mutex); 
    std::map<std::string,dns_entry>::const_iterator const it=
       entries.find(domain);
    return (it==entries.end())?dns_entry():it->second;
  }
  void update_or_add_entry(std::string const& domain,
                           dns_entry const& dns_details)
  {
    std::lock_guard<boost::shared_mutex> lk(entry_mutex);
    entries[domain]=dns_details;
} };

上面代码,find_entry()使用了boost::shared_lock<>实例来保护器共享和只读权限;update_or_add_entry()使用std::lock_guard<>实例来独占访问权限。

嵌套锁

对于一个已经上锁的互斥量多次上锁,会出现未定义行为。然而对于嵌套锁std::recursive_mutex来说,多次上锁不会出现问题。

在互斥量锁住其他线程前,你必须释放你拥有的所有 锁,所以当你调用lock()三次时,你也必须调用unlock()三次。正确使
用 std::lock_guard<std::recursive_mutex>和 std::unique_lock<std::recursice_mutex>可以帮我们处理这些问题。

大多数情况下,嵌套锁是用在可被多线程并发访问的类上,所以其拥有一个互斥量保护其成员数据。每个公共成员函数 都会对互斥量上锁,然后完成对应的功能,之后再解锁互斥量。不过,有时一个公共成员函 数会调用另一个公共函数作为其操作的一部分。

不过上面提高的方案是不推荐的,推荐的做法是——从中提取出一个函数作为类的私有成员, 并且让所有成员函数都对其进行调用,这个私有成员函数不会对互斥量进行上锁(在调用前必 须获得锁)。


关注微信公众号
C++并发编程--第三章--线程间共享数据 1. 线程间共享数据存在的问题 所有线程间共享数据的问题,都是修改数据导致的(竞争条件)。如果所有的共享数据都是只读的,就没问题,因为一个线程所读取的数据不受另一个线程是否正在读取相同的数据而影响。(引用https://blog.youkuaiyun.com/xy_cpp/article/details/80646443)。 2. 利用锁(mutex)保护共享数据 2.1 使用C++11中的std::mutex 在C++11中,你可以通过std::mutex的构造函数创建一个std::mutex实例,通过调用l 阅读详情

相关推荐

windowsC++多线程加锁信号量共享内存

windowsC++多线程加锁信号量共享内存

将读写锁放到共享内存中,实现进程之间对数据的读写访问控制

代码 #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <assert.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <fstream> #include <

CHYabc123456hh的博客 685

ESP32-P4开发板实战:从零配置VSCode环境到点亮MIPI-DSI屏幕(避坑指南)

本文详细介绍了ESP32-P4开发板在VSCode环境下的配置流程,包括SDK安装、idf_component.yml依赖管理,以及MIPI-DSI屏幕驱动的实现方法。通过实战指南帮助开发者避开常见配置陷阱,快速完成从环境搭建到屏幕点亮的全流程,适用于物联网和嵌入式开发场景。

pp12345的博客 742

C++并发编程2——为共享数据加锁(三)

死锁的概念略去不说,死锁有可能发生在使用多个互斥量的场景下,也可能存在没有使用互斥量的场景

小熊糖否——木子兮的自留地 3154

华为防火墙双线路配置实战:5分钟搞定主备自动切换(含健康检查避坑指南)

本文详细介绍了华为防火墙双线路配置实战,包括主备自动切换和健康检查机制的优化技巧。通过智能健康检查机制,华为防火墙能实现毫秒级故障自动切换,确保网络高可用性。文章提供了从架构设计到实战配置的全流程指南,并分享了常见配置误区与解决方案,帮助中小企业快速搭建稳定可靠的网络架构。

weixin_30872337的博客 605

微弱电流检测放大器PCB布线布局设计

微弱电流检测放大器PCB布线布局设计的注意事项,保护环的概念和相关设计。

ydgd118的博客 1万+

Linux进程间通信之互斥锁(共享内存实现),包括C++11的事件,信号量

#pragma once #include <mutex> #include <condition_variable> #include <chrono> #include <string> #include <memory> #ifndef _WIN32 #include <unistd.h> #include <semaphore.h> #include <stdio.h> #include <fcn

阿乐的博客 4050

Ansys Lumerical 启动时出现 Error: Could not connect to Ansys license server specified at 1055@ 的一种解决办法

考虑到 2020 版的时候是直接在全局变量里指定具体地址,但是 2024 版本是写成 1055@localhost ,并且之后在站里搜相关 Ansys 的问题都指向 1055 端口被占用,虽然问题不一样,但是本着死马当活马医,就按照。我最近在跑超透镜结构,听说2024版本现在有GPU加速可以用,就把Lumerical从2020升到2024版本,结果发现一开头的破解办法完全不一样了。一开始安装的时候以为2020没有删干净,导致2024版的安装一直锁着目标地址,解决办法参考。的办法来操作,在关闭了。

qq_51404184的博客 5753

c++实现读写共享锁

一、使用互斥锁和条件变量实现读写锁: [cpp] view plaincopy class readwrite_lock   {   public:       readwrite_lock()           : stat(0)       {       }          void readLock()

lishaoyu的专栏 1023

Gemini国内合规接入指南:API身份链构建与镜像站选型

生成式AI服务接入本质是服务可用性工程,而非单纯网络连通问题。理解大模型API调用原理,关键在于掌握身份认证、权限控制与数据流向三大技术要素。Gemini作为主流多模态模型,其国内可用路径已从‘模拟访问’转向‘能力映射’——聚焦文本生成等核心能力的稳定调用。通过构建七步Google Cloud身份链(含+86实名、国际信用卡核验、Service Account最小权限配置),可实现99.2%高成功率的合规API接入;而教育型、企业型、开发者型三类镜像站则提供差异化过渡方案,均需满足端到端加密、境内CDN托管

weixin_29046035的博客 436

BambuStudio学习笔记:OpenCSG - 实时构造实体几何(CSG)渲染的 OpenGL 方案

**OpenCSG** 是一个基于 **OpenGL** 的 **构造实体几何(CSG)** 实时渲染库,通过 **深度剥离算法** 实现布尔运算(并集、交集、差集)的可视化。其核心目标是简化复杂几何体的交互式建模,适用于 CAD 原型设计、3D 打印预览、教育工具等场景。

zzzkk2009的专栏 929

C++并发编程 -2.线程间共享数据

本章就以在C++中进行安全的数据共享为主题。避免上述及其他潜在问题的发生的同时,将共享数据的优势发挥到最大。

qq_45604814的博客 2003

GATK SNP过滤参数优化:从标准到个性化调整的实践指南

本文深入探讨了GATK SNP过滤参数的个性化调整策略,强调不应盲目套用官方标准参数。文章详细拆解了QD、FS、SOR等关键过滤参数的含义,并提供了通过数据分布分析、文献调研和迭代测试来确定适合自身数据(如动植物重测序)最佳阈值的实践方法,旨在帮助研究者在保留真实变异与剔除假阳性信号之间找到最优平衡。

weixin_29216049的博客 275

C++并发编程实战 第三章 在线程间共享数据

private:public:// 1 在构造函数体中的执行拷贝// 在调用pop前,检查栈是否为空// 在修改堆栈前,分配出返回值data.pop();return res;data.pop();

qq_52758467的博客 530

Vue和Vue-Element-Admin(六):集成中的CORS(跨域资源共享)问题

在vue-element-admin登录集成时候碰到跨域资源共享问题,CORS(Cross-origin resource sharing)是浏览器的技术规范,浏览器可以发起跨域请求但Javascript脚本不能,传统的ajax只能获取在同域名下的资源,但Html5允许ajax发起跨域请求,解决方案有:JSONP、Flash、IFrame、CORS。 一、CORS(跨域资源共享)问题 针对vue-element-admin的登录模块的后端接口完成后,前端调用时候出现报错,因为前端的端口是9527而后.

叶子叶来 9615

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

C++并发编程实战 第三章 线程间共享数据

add_to_list() 和 list_contains() 函数使用 std::lock_guard 来确保对 some_list 的访问是互斥的,即一个线程在修改列表时,其他线程不能读取或修改该列表。除了上述特性外,std::unique_lock 还支持锁所有权的转移,这意味着你可以将一个 std::unique_lock 持有的锁转移给另一个 std::unique_lock 实例。因为两个线程可能尝试在相同的一对实例之间交换数据,但选择了相反的锁定顺序,从而导致死锁。

_ 838

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

《C++并发编程实战》精读总结:第三章 在线程间共享数据

多线程数据共享的问题多是由于对数据的改动引起的,要对共享的数据进行保护,比较直接的方法就是实用互斥和加锁。下面看一个简单的例子,使用到了互斥mutex,和对互斥加锁lock_guard<>。这里,假设一个线程调用add向stack1里添加元素时,如果另外一个线程调用top_value想要看stack顶部的元素是无法做到的,因为add已经锁住了互斥mutex1。注意,互斥标记的是代码。锁住互斥就是锁住标记代码涉及到的共享数据。

见牛羊的博客 299

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C++并发编程2——为保护数据加锁(一)

在应届生面试的时候,很多面试官都会问——“多线程如何共享资源”。在操作系统层面上可以给出若干关键词答案,但是在语言层面,这个问题考虑的就没有那么简单了。

小熊糖否——木子兮的自留地 6318

C++ 加锁的原则

规则1 多线程、进程并行访问共享资源时,一定要加锁保护 说明:共享资源包括全局变量,静态变量,共享内存,文件等。 建议封装像智能指针一样的对象对锁进行管理,比如我们就封装了一个auto_lock,在构造时申请 锁,析构中释放锁,保证不会忘记“解锁”。如果锁的作用范围有限,则可以这样: do { auto_lock lock(&lock); //… }while(0); 规则2 锁的职责单一 说明:每个锁只锁一个唯一共享资源;这样,才能保证锁应用的单一,也能更好的确保加锁的范围尽 量小。

GoodLinGL的博客 2908

16.C++11线程—在线程间共享数据(笔记)

在并发编程中,操作由两个或多个线程负责,它们争先让线程执行各自的操作,而结果取决于它们执行的相对次序,所有这种情况都是条件竞争。有时候,这直观、易懂,因为诸多互斥的用途各异,也会出现棘手的状况,例如,运用多个互斥分别保护多个独立的实例,这些实例属于同一个类。可是,如果选用了固定的次序(两个对象通过参数传入,我们总是先给第一个实例的互斥加锁,再轮到第二个实例的互斥),前面的建议就适得其反:针对两个相同的实例,若两个线程都通过该函数在它们之间互换数据,只是两次调用的参数顺序相反,会导致它们陷入死锁!

C++方向学习笔记 940

《C++并发编程实战》之第3章 线程共享

c++ 并发编程 数据共享

yxqq378287007的博客 1770

C++并发编程之二 在线程间共享数据

C++并发之探索编程二实战

Awesomewan的博客 1966

C++并发编程-3.互斥与死锁

本文介绍如何使用互斥量保证共享数据的安全,并讲述死锁的相关处理方案。

yang_pi_pi的博客 1111
上一篇: C++并发编程2——为共享数据加锁(三)
下一篇: 如何设计高效的C++类
JerkWisdom
博客等级 码龄14年 70粉丝 76原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值