多线程编程之读写锁

多线程编程之读写锁

读写问题是一个经典的同步问题,主要针对保护很少更新的数据结构这种同步情况。

具体的例子:

假设有一个用于存储DNS条目缓存的表,它用来将域名解析为相应的IP地址。通常,一个给定的DNS条目将在很长一段时间里保持不变——在许多情况下,DNS条目会保持数年不变。虽然随着用户访问不同的网站,新的条目可能会被不时地添加到表中,但这一数据却将在其真个生命中保持不变。定期检查缓存条目的有效性是很重要的,但是只是在细节已有实际改变的时候才会需要更新。
虽然更新是罕见的,但他们仍然会发生,并且如果这个缓存可以从多个线程访问,它就需要在更新过程中进行适当的保护,以确保所有线程在读取缓存时都不会看到损坏的数据结构。

如何高效的解决这种同步问题?

我们知道使用std::mutex来保护数据结构就会显得特别悲观,因为这会在数据结构没有进行修改时消除并发读取数据结构的可能,因此我们需要另一种互斥元——读写锁。读写锁考虑到了两个不同的用法:由单个线程独占访问或共享,由多个线程并发访问。
新的C++11标准库并没有直接提供这样的互斥元,尽管已向标准委员会提议。由于这个建议未被接纳,例子使用由boost库提供的实现——boost::shared_mutex。对于更新操作,std::lock_guard<boost::shared_mutex>std::unique_lock<boost::shared_mutex>可用于锁定,以取代相应的std::mutex特化。这样确保了独占访问,就像std::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> lock(entry_mutex);      //使用boost库中的boost::shared_lock进行读锁定
		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> lock(entry_mutex);			//使用C++11库中的std::lock_guard进行写锁定
		entries[domain] = dns_details;
	}
};

find_entry()使用一个boost::shared_lock()实例来保护它,以供共享、只读的访问;多个线程因而可以毫无问题的同时调用find_entry()。另一方面,update_or_add_entry()使用一个std::lock_guard<>实例,在表被更新时提供独占访问;不仅在调用update_or_add_entry()中其他线程被阻止进行更新,调用find_entry() 的线程也会被阻塞。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值