正在连续迭代的线程安全无序映射

时间:2015-05-26 21:43:49

标签: c++ multithreading templates stl

我有可以使用以下模板访问的类集合:

template <typename T> using RegistryMap = std::unordered_map <std::string, T *>;
template <typename T> class Registry {
  static RegistryMap<T> registry;

public:
  static T* get(const std::string& name) {
    auto it = registry.find(name);
    return it == registry.end() ? nullptr : it->second;
  }

  static const RegistryMap<T>& getAll() {
    return registry;
  }

 static bool add(const std::string &name, T *object) {
    T* &store = registry[name];
    if (store)
      return false;
    else {
      store = object;
      return true;
    }
  }

  static bool remove(const std::string &name) {
    auto it = registry.find(name);
    if (it == registry.end())
      return false
    else {
      registry.erase(it);
      return true;
    }
  }
};

此注册表中的许多类定义了一个名为run的方法,线程线程将调用该方法进行紧密循环。在发生这种情况时,其他线程可以使用上述方法在地图中添加/删除元素。

void workerThread() {
     examples = Registry<ExampleClass>::getAll();
     auto it = examples.begin();
     while (true) {
         if (it != examples.end())
             it++->second->run();
         else
             it = examples.begin();
     }
}

有没有办法让这个模板线程安全?我可以向Registry模板类添加静态锁,并在add或remove方法中获取它。但是我该如何处理紧密循环的线程呢?特别是在注册表变得非常大的情况下。如果需要,打开以替换unordered_map并丢失线性查找时间。

2 个答案:

答案 0 :(得分:1)

有数以万计的方式。这是一个非常简单的实现错误。

在您的内部实现中,不要保留一个哈希表,而应保持 p 对哈希表和锁( p 是一些素数)。

要修改(即插入或删除)条目,首先找到其哈希值,然后将其模数为 p 表中的一个,然后锁定并执行操作。

同时,紧密循环线程将遍历 p 组。对于每个组,它将锁定锁,遍历组并释放它。

p 有一个权衡。 p 的值太小(相对于对象总数)将导致锁定争用的概率很高。 p 的值过高将导致紧密循环线程的高锁定 - 有效负载 - 操作开销。

根据具体情况,您可能还需要考虑读写锁,只有修改操作才能进行写访问。

答案 1 :(得分:1)

一种简单的方法是使用循环链表。这根本不需要锁定 - 只需要确保插入和删除是列表本身的原子操作(很容易实现)。

如果线性查找很重要,可以通过在键(字符串...)和列表中的链接之间保持映射来扩展解决方案,以便于删除或执行任何其他操作。