假设有用户存储DNS条目缓存的表,支持多线程读取,但在进行更新时独占访问数据结构,直到它完成了操作。使用 std::mutex 来保护数据结构会在其没有修改时消除并发读取数据结构的可能。这种新的互斥元通常称为读写互斥元,因为它考虑了两种不同的用法:由单个“写”线程独占访问或共享,有多个“读”线程并发访问。

对于更新操作,std::lock_guard<boost::shared_mutex>std::unique_lock<boost::shared_mutex> 可用于锁定,以取代相应的 std::mutex 特化,这确保了独占访问。那些不需要更新数据结构的线程能够转而使用 boost::shared_lock<boost::shared_mutex> 来获得共享访问,这与 std::unique_lock 用起来是相同的,除了多个线程在同一时间、统一 boost::share_mutex 上可能会有共享锁。唯一的限制是,如果任一线程拥有一个共享锁,试图独占锁的线程会被阻塞,直到其他线程全都撤回它们的锁;同样的,如果任一线程具有独占锁,其他线程都不能获取共享锁或独占锁,直到第一个线程撤回了它的锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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 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;
}
}