重新哈希时锁定哈希映射

Locking a Hash Map when Rehashing

我正在尝试创建线程安全的哈希映射。我为哈希映射中的每个存储桶提供了一个互斥向量,以支持哈希映射中每个条目的 reader-writer 锁。

但是,当我想重新哈希映射时,我想锁定整个映射,以便在重新哈希期间不会发生 reads/writes。

我想我需要一个额外的互斥锁,但是我的 Gets/Puts 方法是否也需要获取这个互斥锁?如何仅在重新散列发生时阻止其他线程执行 Reads/Writes 并且在仅发生写入和读取时不相互阻塞?

这是我当前的哈希 table class 的样子:

template<typename K, typename T>
class HashTable {
    int num_buckets_;
    double threshold_ratio_;
    int num_elements_;
    vector<vector<pair<T, K>>> table_;
    vector<mutex> read_write_locks_;
    mutex mu_;

    int GetHash(const K& key) {
        return hash<K>{}(key) % num_buckets_;
    }

    void Rehash() {
        scoped_lock<mutex> lock(mu_);   // Lock the whole table?
        cout << "Threshold Value has been reached. Rehashing...\n";

        vector<vector<T>> new_table(2 * num_buckets_);
        num_buckets_ = 2 * num_buckets_;

        vector<mutex> new_mutexes(2 * num_buckets_);
        read_write_locks_.swap(new_mutexes);
        // TODO : Implementation
    }

public:
    explicit HashTable(int num_buckets) : num_buckets_(num_buckets), threshold_ratio_(0.75), num_elements_(0) {
        table_.resize(num_buckets);
        vector<mutex> temp(num_buckets);
        read_write_locks_.swap(temp);
    }

    void Put(const K& key, const T& val) {
        ++num_elements_;
        if (static_cast<double>(num_elements_) / num_buckets_ > threshold_ratio_) {
            Rehash();
        }
        int hash_val = GetHash(key);
        scoped_lock<mutex> write_lock(read_write_locks_[hash_val]);
        cout << "Putting Key: " << key << ", Hash: "<< hash_val << "  with Value: " << val << '\n';
        table_[hash_val].push_back({val, key}); //TODO: For existing keys it should replace the value, not create a new entry
    }

    T Get(const K& key) {
        int hash_val = GetHash(key);
        scoped_lock<mutex> read_lock(read_write_locks_[hash_val]);

        if (table_[hash_val].size() >= 1) {
            for (const auto& elem : table_[hash_val]) {
                if (elem.second == key) {
                    cout << "Key: " << key << " gets value: " << elem.first << '\n';
                    return elem.first;
                }
            }
        }
        cerr << "Unable to find key in hash table. Terminating Program. \n";
        exit(EXIT_FAILURE);
    }
};

这是想多了。保护整个容器的单个互斥锁就足够了。但是如果你非要实现这种复杂的设计:

  1. 为您的全局容器互斥体使用 std::shared_mutex
  2. 个人 getters/putters 在锁定他们个人的哈希桶之前需要获取全局互斥体上的共享锁。
  3. Rehash 获取排他锁,阻塞所有 getters/putters.