c++并发编程笔记一 除使用锁以外,保护共享变量方法

有些数据只需要在初始化时进行保护,由于是只读数据,后面也不进行更新。这时在初始化完成后,访问变量时仍然先去加锁,就多余和影响效率了。c++标准为这样的场景提供了一个机制:

有些开销大的对象需要延迟初始化,比如数据库连接或者分配大内存。在单线程中需要先判断是否为空,然后再去初始化。在多线程环境下,需要加锁访问,这会导致程序被串行执行,许多人使用

双重检查锁方法:即先判断指针是空的情况下,再去加锁和初始化。不幸的是会导致数据竞争。因为锁外面的读操作并没有和加锁后的写操作同步。即使另外的线程看到了对指针写操作,也不保证看到

了新初始化的对象,后面操作这个对象就可能会出现不正确的结果。这就是数据竞争,会导致未定义结果,无疑要避免这种行为。

    标准提供了std::once_flag和std::call_once来处理这种场景。当std::call_once 返回时,可以确保有一个线程完成了指针的初始化。相比使用锁的方式,开销更小,特别时已经初始化以后。

所以应该尽可能使用这种方式。

   另外一种避免初始化时的数据竞争是采用静态局部变量方式。静态局部变量的初始化发生在控制流首次遇到其定义时候。对于多线程调用,意味着可能存在并发数据竞争问题。对于c++11之前的版本来说,

实际上是有问题的,因为可能每个线程都认为自己是第一个,从而去初始化,也可能在别的线程正在初始化还没有完成时候去使用。在c++11后解决了这个问题,只允许一个线程去初始化,而这个过程中,别的线程

必须等待,所以全部的数据竞争就是哪个线程去实施初始化,不会再有数据并发问题了。

    更一般的场景是保护一个不经常更新的对象。比如DNS数据不经常更新,但偶尔也会有更新,所以也要考虑数据竞争。可以使用读写锁,std::shared_mutex . 一旦线程以共享的方式获取到锁, 别的用独占

方式获取锁的线程就要阻塞,直到所有的共享锁线程都释放锁。同样一旦获取到独占锁,那么使用共享锁的线程也必须等待。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值