【问题标题】:Do we need to lock mutex around std::map<K, V>::find function?我们是否需要在 std::map<K, V>::find 函数周围锁定互斥锁?
【发布时间】:2018-04-09 15:34:25
【问题描述】:

我们在这里:

template<typename TK, typename TV>
class MetaAssociator
{
public:

   void Set(TK key, TV const & value)
   {
      boost::lock_guard<boost::mutex> lock(m_Mutex);
      m_Map[key] = value;
   }

   TV Get(TK key) const
   {
      boost::lock_guard<boost::mutex> lock(m_Mutex); // this one
      std::map<TK,TV>::const_iterator iter = m_Map.find(key);
      return iter == m_Map.end() ? TV() : iter->second;
   }

private:
   mutable boost::mutex m_Mutex;
   std::map<TK,TV> m_Map;
};

我们真的需要在 get 函数中锁定互斥锁吗?我们只提供只读访问。如果我们不这样做呢?

【问题讨论】:

  • 那么,如果在您的 setter 中写入前 8 位后,您尝试读取该值,您认为会发生什么?

标签: c++ multithreading boost mutex


【解决方案1】:

是的,我们需要它。

假设有 2 个线程 A 和 B:

  • 线程 A 正在设置值。
  • 线程 B 正在同时读取这个值。

这里可能会产生数据竞争条件,包括分段错误(线程 B 正在尝试使用不再存在的对象)。

我们可以使用互斥锁来保护这些部分(如您的示例中所示)。另一种选择是使用read and write lock。读写锁的优点是允许并发读访问。

【讨论】:

  • find 本身是否需要互斥锁?我可以使用 find 并且仅当 itr == end 时才使用互斥锁?假设如果单元格存在,我们将不写。
  • @AssafLivne 您可以检查并立即更改其他线程中的数据。这不是解决方案。
【解决方案2】:

当至少一次访问是修改时,从两个执行线程同时访问同一个对象是未定义行为的典型示例,在这种情况下是数据竞争。

因此,除非您有其他方法来保证Set 永远不会与Red 同时被调用(尽管同步放置在程序的其他部分),否则您确实需要一个同步原语。然而,正如其他评论员所建议的那样,std::shared_mutex 可能更适合读/写类型的锁。

【讨论】:

    【解决方案3】:

    问题有两个方面。

    1. 锁定自身:是的,由于潜在的重新排序、部分读/写和其他并行操作需要它
    2. 数据安全:您通过 Get() 获得了结果,然后从映射中删除了该条目(与 getter 和 setter 的保护方式相同),然后尝试访问存储在本地的结果。那应该怎么办?例如,如果 TV 只是指向某物的原始指针,那么您将遇到死链接问题...

    【讨论】:

      【解决方案4】:

      因为当另一个进程正在读取时,某个进程可能正在写入。

      检查经典的“Readers Writers Problem”

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-31
        • 2010-09-12
        • 2011-12-01
        • 2011-09-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多