互斥映射数据结构

时间:2013-05-10 22:19:52

标签: c++ data-structures asynchronous concurrency mutex

问题

  • 我有一个目录D,我想将(K, V)对放入
  • void save(K, V)将内容为K的文件名V保存到目录D
    • 已经"开火而忘记"语义 - 函数可能在实际将文件保存到磁盘之前返回
  • 目录D是定义C函数的类save的字段
  • void save(K, V)的调用应该同时运行
    • 使用tbb::task进行并发
    • 同一个键不能同时运行两个文件写入
    • 也就是说,如果两个线程同时调用save(K, V1)save(K, V2),则结果应该是D中名为K的文件,其内容等于< em> V1 V2(但未损坏)

计划方法

  • 选择将H映射到K
  • 的哈希函数std::size_t
  • 选择一个整数N > 1
  • 为类C提供一组互斥tbb::mutex mutex_map[N]
  • void save(K, V)等待获取mutex_map[H(K) % N]上的锁以执行其文件写入

的问题

  • 这是一种明智的做法吗?
  • 你能想到一个可能比这更有优势的替代方案吗?
  • 是否有一些tbb数据结构已经封装了这个互斥映射的概念?
    • 想象std::map<TKey, tbb::mutex>之类的东西,但接口会同时显示每个可能的键的外观,并同时具有相关的互斥锁。

2 个答案:

答案 0 :(得分:2)

是的,这是一种非常明智的做法。我想不出另一种选择(除了使用std::mutex代替tbb:mutex之类的简单替代方案。)

与您认为同时锁定的互斥锁数量相比,您应该选择N大。 birthday paradox表示如果您希望 k 线程同时尝试锁定,则至少有一次虚假哈希冲突的概率大于50%,直到您获得N > 0(K 2

我不知道tbb数据结构就像互斥体地图。但内部我相信tbb :: malloc使用你建议的技巧(线程被随机分配给独立的malloc数据结构),并且实现了tbb :: concurrent_hash_map,这样就有一个互斥锁哈希桶。

答案 1 :(得分:0)

我对后代的实施

#include <vector>
#include <functional>
#include <tbb/mutex.h> //could of course use std::mutex instead, if available

template <typename Key, typename Hash = std::hash<Key>>
class mutex_map
{
public:
    typedef Key key_type;
    typedef tbb::mutex value_type;
    static const std::size_t default_bucket_count = 16;

private:
    std::vector<value_type> mutexes;
    Hash hash;

public:
    mutex_map(
        std::size_t bucket_count = default_bucket_count,
        const Hash& hash = Hash())
        : hash(hash)
    {
        mutexes.resize(bucket_count);
    }

    std::size_t size() const
    {
        return mutexes.size();
    }

    value_type& get(const Key& key)
    {
        auto n = hash(key) % size();
        n += (n < 0) * size();
        return mutexes[n];
    }
};