6. 保护共享数据的替代措施

保护共享数据的替代措施

互斥量是保护数据的一种通用错失,但并不是唯一错失,这里有很多的替代方法可以在一些特定的情况下,提供更加合适的保护


  1. 共享数据初始化过程的保护
    假设对于一个共享源,构造的代价非常昂贵,在单线程中,通常采用延迟初始化的方法例子如下;
    shard_ptr<resource> resource_ptr;
    void foo(){
    	if(resource_ptr == nullptr){
    		resource_ptr.reset(new resource);
    	}
    	resource_ptr->dowork();
    }
    
    上述代码在单线程中是能够稳定运行的,但是在多线程中就会存在一定的问题,因此,在多线程中,会对resource_ptr加锁保护,代码如下
    shared_ptr<resource>resource_ptr;
    mutex m;
    void foo(){
    	lock_guard<mutex>loc(m);
    	if(resource_ptr == nullptr){
    		resource_ptr.reset(new resource);
    	}
    	loc.unlock();
    	resource_ptr->dowork();
    }
    
    上述代码虽然解决了线程安全的问题,但是,由于resource_ptr只需要初始化一次,但后面每次调用foo的时候,都需要加锁检查resource_ptr(虽然我们已经知道肯定已经进行了初始化)。
    人们对这段代码进行了各种改造,包括声名狼藉的双检查锁(为什么说他声名狼藉,具体原因在此不多加说明,感兴趣的读者可以查看网上的说法
  • C++的保护方法
    在C++中提供了std::once_flagstd::call_once来处理这样的情况,比起锁住互斥量,显示检查指针初始化来说,每个线程只需要使用call_once,在这个函数结束的时候,就能安全地知道指针是否已经被其他线程初始化了,消耗明显更少,具体操作如下所示;
    shared_ptr<resource>resource_ptr;
    once_flag resource_flag;
    void init(){
      resouce_ptr.reset(new resource);
    }
    void foo(){
      call_once(resource_flag,init);
      resource_ptr->dowork();
    }
    
    当作为类成员的时候,需要传入this指针具体如下;
    class A{
    	shared_ptr<m>ptr;
    	once_flag ptr_flag;
    	void init(){
    	  ptr.reset(new m);
    	}
    	void foo(){
    	  call_once(ptr_flag,init,this);
    	  ptr->dowork()''
    	}
    }
    
    类似于thread和bind的构造方法,注意一点,mutex和once_flag实力都是不能拷贝或者移动的

  1. 保护很少更新的数据结构
    这里需要用到另外一种锁,叫读者-作者锁,它允许两种不同的使用方法,一个作者线程独占访问和共享访问,让多个读者线程并发访问由于c++标砖中没有这样的方法,但是boost库中提供了这样的方法,示例代码如下所示:
    class A;
    class A{
    	mutable boost::shared_mutex sm;
    	std::mutex m;
    	void read(){
    	  boost::shared_lock<boost::shared mutex>sl(sm);
    	  ...
    	}
    	vodi write(){
    	  std::lock_guard<mutex>loc(m);
    	  ...
    	}
    }
    

本文作者:^江流儿^

本文链接:https://www.cnblogs.com/hhyandcpp/p/17040624.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ^江流儿^  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.