STL的线程安全解决方案

AMESim柱塞泵建模全指南:从HCD库搭建到联合仿真 液压系统仿真中,轴向柱塞泵的建模始终是难点与热点。柱塞泵结构紧凑、功率密度高,在工程机械与航空航天领域应用广泛,然而其运动学与流体细节深度耦合,给仿真带来不小挑战。AMESim平台中的HCD库提供了一种从物理结构出发的建模思路,将柱塞泵分解为容积腔、节流口与机械约束等基础单元,从而真实刻画柱塞腔压力波动、配流特性和容积效率等关键行为,摆脱黑盒模型的局限。基于机理建模的仿真结果,可用于泵参数优化、故障特征分析以及控制策略验证。进一步结合AMESim与Simulink联合仿真,可以高效开发变量泵排量控制系统,研 阅读详情

  由于STL不是线程安全的, 所以在每一次插入元素,删除元素,读取元素时,必须保证原子操作.
  读取元素也许要原子? 嗯,是的. 因为你得到了一个迭代器后, 这个迭代器对应的容器可能被别的线程修改!

 所以(下面来自<< Effective STL >> 条款十二):

  • 在每次调用容器的成员函数期间都要锁定该容器。
  • 在每个容器返回的迭代器(例如通过调用begin或end)的生存期之内都要锁定该容器。
  • 在每个在容器上调用的算法执行期间锁定该容器。(这事实上没有意义,因为,正如条款32所解释的,算法没有办法识别出它们正在操作着的容器。不过,我们将在这里检验这个选项,因为它的意义在于看看为什么即使是可能的它也不能工作。)

下面是一个巧妙的解决方案:
转自:STL线程安全的解决方法

Multithreading Issues
  STL is not thread protected, so you must provide locks on your collections if they will be used in multithreaded environment. The standard locking mechanisms of Mutexes, Semaphores and Critical Sections can be used. One simple mechanism for providing locking is to declare a lock class. In this class the constructor creates the lock, and the destructor destroys the lock. Then provide lock() and unlock() methods. For example:

class Lock
{
public:
    HANDLE    _hMutex;            // used to lock/unlock object

    Lock() : _hMutex(NULL)
    { _hMutex = ::CreateMutex( NULL, false,NULL) ); }

    virtual ~Lock() { ::CloseHandle( _hMutex ); }

    bool lock ()
    {
        if ( _hMutex == NULL )
            return false;
        WaitForSingleObject( _hMutex, INFINITE );
        return true;
    }

    void unlock () { ReleaseMutex(_hMutex);      }
};

  Then declare a class that is derived from one of the STL collections, and in the class override the access methods to the collection that might cause an insertion or deletion of an element. For example a general vector class would be:

template <class T>
class LockVector : vector<T>, Lock
{
public:
    LockVector () : vector<T>(), Lock()
    {}
    virtual LockVector ()
    {}

    void insert ( T & obj )
    {
        if ( !lock())
            return;
        vector<T>::push_back (obj);
        unlock();
    }
};

条款12:对STL容器线程安全性的期待少一些
  标准C++的世界是相当保守和陈旧的。在这个纯洁的世界,所有可执行文件都是静态链接的。不存在内存映射文件和共享内存。没有窗口系统,没有网络,没有数据库,没有其他进程。在这种情况下,当发现标准没有提到任何关于线程的东西时你不该感到惊讶。你对STL的线程安全有的第一个想法应该是它将因实现而不同。
  当然,多线程程序是很普遍的,所以大部分STL厂商努力使他们的实现在多线程环境中可以正常工作。但是,即使他们做得很好,大部分仍由你完成,而理解为什么会这样是很重要的。
  在STL容器(和大多数厂商的愿望)里对多线程支持的黄金规则已经由SGI定义,并且在它们的STL网站[21]上发布。大体上说,你能从实现里确定的最多是下列内容:

  多个读取者是安全的。多线程可能同时读取一个容器的内容,这将正确地执行。当然,在读取时不能有任何写入者操作这个容器。
  对不同容器的多个写入者是安全的。多线程可以同时写不同的容器。
  就这些了,那么让我解释你可以期望的是什么,而不是你可以确定的。有些实现提供这些保证,但是有些不。
  写多线程的代码很难,很多程序员希望STL实现是完全线程安全的。如果是那样,程序员可以不再需要自己做并行控制。毫无疑问这将带来很多方便,但这也非常难实现。一个库可能试图以下列方式实现这样完全线程安全的容器:
  在每次调用容器的成员函数期间都要锁定该容器。
  在每个容器返回的迭代器(例如通过调用begin或end)的生存期之内都要锁定该容器。
  在每个在容器上调用的算法执行期间锁定该容器。(这事实上没有意义,因为,正如条款32所解释的,算法没有办法识别出它们正在操作的容器。不过,我们将在这里检验这个选项,因为它的教育意义在于看看为什么即使是可能的它也不能工作。)
  现在考虑下列代码。它搜寻一个vector中第一次出现5这个值的地方,而且,如果它找到了,就把这个值改为0。

vector<int> v;
vector<int>::iterator first5(find(v.begin(), v.end(), 5)); // 行1
if (first5 != v.end()){     // 行2
    *first5 = 0;     // 行3
}

  在多线程环境里,另一个线程可能在行1完成之后立刻修改v中的数据。如果是那样,行2对first5和v.end的检测将是无意义的,因为v的值可能和它们在行1结束时的值不同。实际上,这样的检测会产生未定义的结果,因为另一线程可能插在行1和行2之间,使first5失效,或许通过进行一次插入操作造成vector重新分配它的内在内存。(那将使vector全部的迭代器失效。关于重新分配行为的细节,参见条款14。)类似的,行3中对*first5的赋值是不安全的,因为另一个线程可能在行2和行3之间执行,并以某种方式使first5失效,可能通过删除它指向(或至少曾经指向)的元素。

  在上面列举的锁定方法都不能防止这些问题。行1中begin和end调用都返回得很快,以至于不能提供任何帮助,它们产生的迭代器只持续到这行的结束,而且find也在那行返回。

  要让上面的代码成为线程安全的,v 必须从行1到行3保持锁定,很难想象STL实现怎么能自动推断出这个。记住同步原语(例如,信号灯,互斥量,等等)通常开销很大,更难想象实现怎么在程序没有明显性能损失的情况下做到前面所说的——以这样的一种方式设计——让最多一个线程在1-3行的过程中能访问v。

  这样的考虑解释了为什么你不能期望任何STL实现让你的线程麻烦消失。取而代之的是,你必须手工对付这些情况中的同步控制。 在这个例子里,你可以像这样做:

vector<int> v;
...
getMutexFor(v);
vector<int>::iterator first5(find(v.begin(), v.end(), 5));
    if (first5 != v.end()) {      // 这里现在安全了
        *first5 = 0;      // 这里也是
    }
releaseMutexFor(v);

  一个更面向对象的解决方案是创建一个Lock类,在它的构造函数里获得互斥量并在它的析构函数里释放它,这样使getMutexFor和releaseMutexFor的调用不匹配的机会减到最小。这样的一个类(其实是一个类模板)基本是这样的:

template <typename Container>     // 获取和释放容器的互斥量
class Lock {                      // 的类的模板核心;
public:                           // 忽略了很多细节   
    Lock(const Containers container) : c(container)
    {
        getMutexFor(c);    // 在构造函数获取互斥量
    } 

    ~Lock()
    {
        releaseMutexFor(c);   // 在析构函数里释放它
    }
private:
    const Container& c;
};

  使用一个类(像Lock)来管理资源的生存期(例如互斥量)的办法通常称为资源获得即初始化,你应该能在任何全面的C++教材里读到它。一个好的开端是Stroustrup的《The C++ Programming Language》[7],因为Stroustrup普及了这个惯用法,但你也可以转到《More Effective C++》的条款9。不管你参考了什么来源,记住上述Lock是被剥离到最原始的本质的。一个工业强度的版本需要很多改进,但是那样的扩充与STL无关。而且这个最小化的Lock已经足够看出我们可以怎么把它用于我们一直考虑的例子:

vector<int>  v;
...
{               // 建立新块;
    Lock<vector<int> > lock(v);     // 获取互斥量
    vector<int>::iterator first5(find(v.begin(), v.end(), 5));
    if (first5 != v.end()) {
        *first5 = 0;
    }
}        // 关闭块,自动
        // 释放互斥量

  因为Lock对象在Lock的析构函数里释放容器的的互斥量,所以在互斥量需要释放时就销毁Lock是很重要的。为了让这件事发生,我们建立一个里面定义了Lock的新块,而且当我们不再需要互斥量时就关闭那个块。这听上去像我们只是用关闭新块的需要换取了调用releaseMutexFor的需要,但是这是错误的评价。如果我们忘记为Lock建立一个新块,互斥量一样会释放,但是它可能发生得比它应该的更晚——一直到控制到达封闭块的末端。如果我们忘记调用releaseMutexFor,我们将不会释放互斥量。
  而且,这种基于Lock的方法在有异常的情况下是稳健的。C++保证如果抛出了异常,局部对象就会被销毁,所以即使当我们正在使用Lock对象时有异常抛出,Lock也将释放它的互斥量。如果我们依赖手工调用getMutexFor和releaseMutexFor,那么在调用getMutexFor之后releaseMutexFor之前如果有异常抛出,我们将不会释放互斥量。
  异常和资源管理是重要的,但是它们不是本条款的主题。本条款是关于STL里的线程安全。当涉及到线程安全和STL容器时,你可以确定库实现允许在一个容器上的多读取者和不同容器上的多写入者。你不能希望库免除对手工并行控制的需要,而且你完全不能依赖于任何线程支持。

参考文章:
STL的线程安全解决方案

c++ stl list 是否需要互斥保护

c++ stl list 是否需要互斥保护

【数据同化第二期】数据同化中三大理论基础之一(最小方差估计) 【数据同化第二期】深入理解数据同化及经典案例(最小方差估计) 阅读详情

相关推荐

我用WorkBuddy“克隆“了一个我,从此每句话像我自己说的

各位,做这件事花了多长时间?准备样本可能要半小时,提炼风格十分钟,保存固化再花十分钟。加起来不到一个小时。但这一个小时之后呢?你就拥有了一个"永远在线的文字替身"。以后写口播稿,打开WorkBuddy跟它说;写课程逐字稿,跟它说;写公众号文章,也跟它说。写出来的东西,你的学员一看——“嘿,这不就是翟猛老师说的嘛。说到这儿,可能有人会问:老师,我的风格有那么重要吗?AI写的不都挺好的吗?各位你想想看,你为什么愿意听某个老师的课?不只是因为他讲的内容好,更是因为你喜欢他讲话的方式。

weixin_39284145的博客 818

STL容器的线程安全性?

需要注意的是,即使STL容器本身是线程安全的,但在多线程环境下使用时,仍需要注意对迭代器的操作可能会引起容器的线程安全问题。如 map,set,unordered_map,unordered_set)和无序容器(如 unordered_map,unordered_set)的线程安全版本为其加了。(如 vector,deque,list,forward_list,string)的线程安全版本为其加了 _safe 后缀,例如 std::vector。t 后缀,例如 std::map_mt。

weixin_42195477的博客 1971

[Unity实战]热更新如何预防过度裁剪

假设你现在有一个游戏客户端,客户端只打包了入口场景,游戏场景都存放在了AB包。

u012587406的博客 1604

vector容器的简单介绍与使用

C++中Vector容器的使用方式了解Vector容器C++中容器使用方式读取容器的内容直接改变容器的大小 了解Vector容器 Vector容器就是能够存储很多数据,但是必须是相同类型的。类似数组,但是按需分配。 容器的构造方式 1、需要添加头文件 2、vector <类型> 容器名 C++中容器使用方式 #include<iostream> #include<ve...

在路上的博客 674

嵌入式学习的书单推荐

以上是一些优秀的嵌入式学习书单推荐。选择适合自己的学习材料对于学习嵌入式系统非常重要。每一本书籍都有其独特的优势和特点,读者可以根据自己的学习目标和兴趣选择合适的书籍。同时,我们也要注意不断实践和探索,结合实际项目和项目经验,不断提升自己的嵌入式技术水平。希望本文的推荐能够帮助大家在嵌入式学习的道路上取得更好的成果。

新程序圆 1979

ADS仿真设计平行定向耦合器学习笔记

ADS仿真设计平行定向耦合器

qq_36521926的博客 1万+

【Linux】线程池|单例模式|STL、智能指针线程安全|读者写者问题

【Linux】线程池|单例模式|STL、智能指针线程安全|读者写者问题

weixin_60478154的博客 2197

GD-Link离线烧录全攻略:从配置到一键下载的保姆级教程

本文详细介绍了GD-Link离线烧录的全流程,从硬件准备到软件配置,再到一键下载的实战技巧。通过保姆级教程,帮助工程师快速掌握国产MCU的离线烧录技术,适用于产线批量烧录和现场设备维护等场景,显著提升工作效率。

ww90123的博客 649

STL 线程安全

所有的 STL 容器在多线程环境中都需要使用同步机制来确保线程安全。使用进行同步是一个常见的方法。通过仔细设计锁的使用范围和策略,可以在保证线程安全的同时,尽量减少对性能的影响。

wuxiaoyu0806的博客 1195

本地化搭建DeepSeek+RAGFlow,构建个人知识库

本地化搭建DeepSeek+RAGFlow,构建个人知识库。至少32G以上内存、500G以上空余磁盘空间。

gogospecter的专栏 7424

36. 在 SAP Integration Suite 里打通入站 HTTP:iFlow 端点鉴权、角色授权与多节点 403 排障实战

本文探讨了SAP Cloud Integration中HTTP入站连接的认证与授权机制。在Cloud Foundry环境下,认证(证明身份)和授权(权限控制)需分开处理:认证可采用Basic、OAuth或mTLS等方式,授权则通过角色实现。文章详细解析了两种主流配置路径:基于IdP用户的Basic认证(需配置Role Collection)和基于OAuth Client/Service Instance的系统调用(通过Service Key管理权限)。特别指出ABAP系统在多节点环境下可能因cookie编码

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 320

STL线程安全讨论

最近在回头看STL里面的实现,也在进一步研究高性能服务器编程方面的东西,就想到那STL在多线程情况下是否安全呢? 记录 STL是数据结构和算法的精妙实现,因此为了追求极致的效率,内部并没有给所有的操作加锁。对于STL的容器而言,只有下面这两种情况可以保证线程安全: 多个线程同时读取同一个容器的内容 多个线程同时写不同的容器 其他的情况,比方说:多个线程同时读、写同一个容器。这就不是线程安全...

冷山不生云 1929

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

STL的线程安全解决方案.

  由于STL不是线程安全的, 所以在每一次插入元素,删除元素,读取元素时,必须保证原子操作.  读取元素也许要原子? 嗯,是的. 因为你得到了一个迭代器后, 这个迭代器对应的容器可能被别的线程修改! 所以(下面来自> 条款十二): 1)在每次调用容器的成员函数期间都要锁定该容器。 2)在每个容器返回的迭代器(例如通过调用begin或end)的生存期之内都要锁定该容器。

xuhao_xuhao的专栏 415

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

stl是不是线程安全的

STL的线程安全解决方案

m0_46598535的博客 882

STL容器的线程安全?

接上一篇STL容器删除操作继续,STL使用起来方便,还有自动内存管理,再结合合适的泛型算法大大提高了我们编程的效率,于是我们“肆无忌惮”的使用在自己的程序中。但是只要你有“肆无忌惮”的态度,你终归是要走上弯路的,比如其线程安全问题。先从《Effective STL》进行搬运。线程安全的情况多个读取者是安全的。多线程可能同时读取一个容器的内容,这将正确地执行。当然,在读取时不能 有任何写入者操作这个

u012730075的专栏 3504

STL容器的线程安全

STL容器是线程不安全的。 线程安全的情况 多个读取者是安全的。多线程可能同时读取一个容器的内容,这将正确地执行。当然,在读取时不能 有任何写入者操作这个容器。 对不同容器的多个写入者是安全的。多线程可以同时写不同的容器。 线程不安全的情况 在对同一个容器进行多线程的读写、写操作时。 在每次调用容器的成员函数期间都要锁定该容器。 在每个容器返回的迭代器(例如通过调用begin或end)的生存期之内都要锁定该容器。 在每个在容器上调用的算法执行

jusu10的博客 2913

hashmap扩容线程安全问题_C++ STL容器如何解决线程安全的问题?

互联网小知识2020/9/25C++ STL容器如何解决线程安全的问题?比如一个 很大的vector,线程A在做push_back(频率低), 线程B,C,D,E,F 在做reading(频率较高),那么这样应该不是线程安全的,查了些资料,都说要给vector加锁。但是如果vector 很大,这样效率应该会很低。有没有其他解决方案?众所周知,STL容器不是线程安全的。对于vector,即...

weixin_35866960的博客 948

STL容器线程安全

摘抄整理自《Effective STL》 对STL容器线程安全性的期待现实一些 标准C++的世界是相当保守和陈旧的。在这个纯洁的世界,所有可执行文件都是静态链接的。不存在内存映射文件和共享内存。没有窗口系统,没有网络,没有数据库,没有其他进程。在这种情况下,当发现标准没有提到任何关于线程的东西时你不该感到惊讶。你对STL的线程安全有的第一个想法应该是它将因实现而不同。 当然,多线程程序是

bxw1992的博客 708

C++ STL 容器的线程安全问题

当线程A遍历map时,线程B的插入操作可能导致树结构重组,使线程A的迭代器失效。解决方案包括:使用读写锁(std::shared_mutex)保护整个遍历过程,或转为线程安全容器(如Intel TBB的concurrent_hash_map)。C++17引入的std::scoped_lock能简化多锁管理,而第三方库(如Folly的ConcurrentHashMap)则提供现成的高性能线程安全容器。例如,std::list的size()方法可能缓存长度值,多线程并发修改时缓存可能不同步。

psdzur_793的博客 253

STL std:string引起的User breakpoint exception/User breakpoint called from code at

SYMPTOMS: 程序崩溃,弹出 User breakpoint called from code at 0x????????对话框; 崩溃时的调用栈有如下几种常见情形:(1)TDLL! 7c92120e()NTDLL! 7c96b460()NTDLL! 7c98ee40()NTDLL! 7c96b3a2()NTDLL! 7c93aa2b()_heap_alloc_base(unsigned int 80) line 200_heap_alloc_dbg(unsigned int 33, int 1, c

铭星的专栏 5093
上一篇: 多屏幕显示
下一篇: C++中虚析构函数的作用
xianjian_x
博客等级 码龄14年 231粉丝 43原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值