21xrx.com
2024-12-22 18:19:03 Sunday
登录
文章检索 我的文章 写文章
C++线程安全的HashMap实现
2023-07-02 00:37:39 深夜i     --     --
C++ 线程安全 HashMap 实现

在C++编程中,HashMap是一个常见的数据结构,它可以帮助我们快速地存储和检索键值对。然而,由于多线程的存在,当多个线程同时访问同一个HashMap时,可能会发生数据竞争问题,导致程序崩溃或者结果不正确。因此,在编写C++的HashMap时,必须格外注意线程安全性。

下面,我们来介绍一种线程安全的HashMap的实现方式。该实现方式基于C++11中的标准库,使用std::unordered_map作为底层容器,并使用互斥量来实现对HashMap的并发访问控制。

首先,我们需要定义一个线程安全的HashMap类,其中包含以下成员变量和函数:


template <typename Key, typename Value>

class ThreadSafeHashMap {

private:

 std::unordered_map<Key, Value> data_; // 底层容器

 std::vector<std::mutex> locks_; // 互斥量数组

 std::hash<Key> hash_; // 哈希函数

 size_t n_locks_; // 互斥量数量,通常设置为CPU核心数量的两倍

public:

 ThreadSafeHashMap(size_t n_locks = std::thread::hardware_concurrency() * 2);

 void insert(const Key& key, const Value& value);

 bool find(const Key& key, Value& value);

 bool erase(const Key& key);

};

- data_:底层容器,使用std::unordered_map实现。

- locks_:互斥量数组,用于控制对HashMap的并发访问,大小通常设置为CPU核心数量的两倍。

- hash_:哈希函数,用于将键转换为对应的哈希值。

- n_locks_:互斥量数量,通常设置为CPU核心数量的两倍。

接下来,我们来实现insert()函数,该函数用于向HashMap中插入一个键值对。为了实现线程安全,我们需要先根据键的哈希值计算出对应的互斥量索引,并使用该互斥量对锁进行保护,从而防止多个线程同时修改同一个桶。代码实现如下:


template <typename Key, typename Value>

void ThreadSafeHashMap<Key, Value>::insert(const Key& key, const Value& value) {

 size_t bucket = hash_(key) % locks_.size();

 std::lock_guard<std::mutex> guard(locks_[bucket]);

 auto iter = data_.find(key);

 if (iter == data_.end()) {

  data_.insert(std::make_pair(key, value));

 } else

  iter->second = value;

 

}

在insert()函数中,首先根据key计算出互斥量的索引bucket,然后使用std::lock_guard 保护锁,防止多个线程同时修改同一个桶。接着,我们使用std::unordered_map的find()函数来查找key是否已经存在,如果不存在,则使用std::unordered_map的insert()函数插入新的键值对,否则更新已有的键值对的值。由于我们在桶内使用了互斥量保护,因此不同的线程可以同时对不同的桶进行访问,从而提高了效率。

接下来,我们来实现find()函数,该函数用于查找给定的键是否存在,并返回对应的值。代码实现如下:


template <typename Key, typename Value>

bool ThreadSafeHashMap<Key, Value>::find(const Key& key, Value& value) {

 size_t bucket = hash_(key) % locks_.size();

 std::lock_guard<std::mutex> guard(locks_[bucket]);

 auto iter = data_.find(key);

 if (iter != data_.end())

  value = iter->second;

  return true;

  else

  return false;

 

}

在find()函数中,我们先根据key计算出互斥量的索引bucket,并使用std::lock_guard 保护锁。然后,我们使用std::unordered_map的find()函数查找key是否存在,如果存在,则将对应的值保存到value中,并返回true,否则返回false。同样地,由于我们在桶内使用了互斥量保护,因此不同的线程可以同时对不同的桶进行访问,从而提高了效率。

最后,我们来实现erase()函数,该函数用于删除给定的键值对。代码实现如下:


template <typename Key, typename Value>

bool ThreadSafeHashMap<Key, Value>::erase(const Key& key) {

 size_t bucket = hash_(key) % locks_.size();

 std::lock_guard<std::mutex> guard(locks_[bucket]);

 return data_.erase(key);

}

在erase()函数中,我们同样根据key计算出互斥量的索引bucket,并使用std::lock_guard 保护锁。然后,我们使用std::unordered_map的erase()函数删除对应的键值对,并返回删除是否成功的结果。

总之,线程安全的HashMap实现需要考虑到并发访问控制,通过使用互斥量对桶进行保护,可以有效地避免数据竞争和访问冲突问题。我们可以使用std::unordered_map作为底层容器,同时根据桶数量合理设置互斥量的数量,从而提高线程安全性和程序的性能表现。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复