【问题标题】:multiple threads performing writes?多个线程执行写入?
【发布时间】:2013-07-27 17:51:48
【问题描述】:

我希望有人能就多线程如何写入一个公共容器(例如地图)提出建议。在某些线程可能使用 Boost 和 C++ 共享相同密钥的场景中

映射可能是 std::map 类型,不同的线程访问对象以修改不同的数据成员。每个线程会在点击 unique_lock 后等待当前线程完成后再继续吗?

会不会像本例那样每个线程进入临界区一样简单:

//somewhere within the code
boost::unique_lock mutex;

void modifyMap(const std::string& key,const unsigned int dataX,
               const unsigned int dataY)
{
     // would each thread wait for exclusive access?
    boost::unique_lock<boost::shared_mutex> lock (mutex);

    // i now have exclusive access no race conditions;
    m_map.find(key)->second.setDataX(dataX);
    m_map.find(key)->second.setDataX(dataY);
}

提前致谢

【问题讨论】:

标签: c++ multithreading boost


【解决方案1】:

您应该创建数据结构的线程安全实现。它可以是基于锁的(例如通过使用互斥体实现)或无锁的(使用 C++11 和 boost 支持的原子操作或内存排序)。

我可以简要描述一下基于锁的方法。例如,您可能想要设计一个线程安全的链表。如果您的线程只执行读取操作,那么一切都是安全的。另一方面,如果您尝试写入此数据结构,您可能需要列表中的上一个和下一个节点指针(如果它是双链接的,您需要更新它们的指针以指向插入的节点)并且在您修改它们时其他一些线程可能会读取不正确的指针数据,因此您需要锁定要在其间插入新节点的两个节点。这会创建序列化(其他线程等待互斥锁被解锁)并减少并发的可能性。

带有查找表的完整示例可在 Anthony Williams 所著的《C++ 并发:实用多线程》一书中第 171 页,清单 6.11 中找到。本书本身是使用最新 C++ 标准进行多线程编程的良好开端,因为本书的作者还设计了 boost::thread 和 C++11 线程库。

更新:为了使您的示例适用于读/写(如果您需要更多操作,您还需要保护它们)您最好使用 boost::shared_mutex 本质上允许多读单写访问:如果一个线程想要写而不是获得排他锁,所有其他线程将不得不等待。这是一些代码:

template <typename mapType>
class threadSafeMap {

boost::shared_mutex map_mutex;
mapType* m_map;

public:

threadSafeMap() {
    m_map = new mapType();
}


void modifyMap(std::string& key,const unsigned int dataX,
               const unsigned int dataY)
{
    //std::lock_guard in c++11. std::shared_mutex is going to be available in C++14
    //acquire exclusive access - other threads wait
    boost::lock_guard<boost::shared_mutex> lck(map_mutex); 

    m_map.find(key)->second.setDataX(dataX);
    m_map.find(key)->second.setDataX(dataY);
}


int getValueByKey(std::string& key)
{
    //std::lock_guard in c++11. std::shared_mutex is going to be available in C++11
    //acquire shared access - other threads can read. If the other thread needs access it has to wait for a fully unlocked state.
    boost::shared_lock<boost::shared_mutex> lck(map_mutex);

    return m_map.getValue(key);
}


~threadSafeMap() {
    delete m_map;
}


};

Lock-guard 对象被破坏,互斥锁在生命周期结束时被解锁。 mapType 模板可以替换为您的地图类型。

【讨论】:

  • 感谢您的回复,那么我上面的示例是否有效?简而言之,我只想知道访问上述函数的多个线程是否会阻塞,直到具有独占访问权限的线程退出(下一个线程将继续修改映射)。这是我正在寻找的行为
  • 我添加了一些代码。你应该使用 boost::shared_mutex, boost::lock_guard 来写, boost::shared_lock 来读。其他操作如果需要也可以同样修改。
  • 非常感谢 Dmirty,这有助于澄清很多问题,只有一个问题,升级到唯一锁也可以吗?
  • 如果您想以与std::boost::lock_guard 相同的方式使用std::boost::unique_lock,则可以执行以下操作:boost::unique_lock&lt;boost::shared_mutex&gt; ulck = boost::unique_lock(map_mutex); ulck.lock(); 或者您可以显式使用显式构造函数进行强制转换 - 示例 (3) en.cppreference.com/w/cpp/thread/unique_lock/unique_lockunique_locklock_guard 更灵活。
  • 对不起,我忘记了boost::defer_lock。应该是:boost::unique_lock&lt;boost::shared_mutex&gt; ulck = boost::unique_lock(map_mutex, boost::defer_lock);.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
相关资源
最近更新 更多