如何确保两个线程中的两个类编写相同的变量线程安全?

时间:2017-03-21 14:27:18

标签: c++ multithreading mutex

我有两个同时在2个线程中运行的类,比如class A和class BA正在从某个API收集数据并继续将更新的数据推送到{ {1}} unordered-map。在同一时间B->m正在使用数据创建自定义类B,代码如下:

班级Bar

A

班级if(m.size() > 0){ //mtx.lock(); lock = B->lock; if(lock == false){ lock = true; B->m = m; lock = false; } m.clear(); //mtx.unlock(); }

B

从这里可以看出,我尝试通过使用一个名为 while(true){ if(m.size() > 0){ //mtx.lock(); if(lock == false){ lock = true; for (auto it : m) { std::string symbol = it.first; std::vector<double> v = it.second; Bar b; b.open = v[0]; b.high = v[1]; bars.push_back(b); } m.clear(); lock = false; } //mtx.unlock(); }} 的布尔值来手动实现一个互斥体,当我编译有时它有时会完成seg fault,我认为是因为边缘情况:当我设置{在课程lock中{1}} locktrue课刚刚跳过BA正在读取按if(lock == false)更改的数据。我的问题是,如何避免这种情况发生?

2 个答案:

答案 0 :(得分:2)

手动互斥实现不起作用(至少不是一种简单的方法)。例如从编译器的角度来看这个

lock = strategy->lock;
if(lock == false){
  lock = true;
  B->m = m;     
  lock = false;
}

可以重新安排到此

lock = strategy->lock;
if(lock == false){
  B->m = m;
}

因为单线程结果(如果你不另外说明,这是编译器的默认观点)是完全相同的。

还有其他原因可能会失败,例如部分对象填充。通常是复杂的东西。

因此,您必须使用您正在使用的库为您提供的某个同步对象。对于C ++ 11及更高版本,您只需使用std::mutex

#include <mutex>
std::mutex my_mutex;
...

// some code
{
    // lock resource
    std::lock_guard<std::mutex> lg(my_mutex);
    B->m = m;
}
// automatically releases the lock and continues the execution

答案 1 :(得分:1)

你需要std :: mutex和std :: condition_variable。

std::mutex用于保护代码免受未定义的行为的影响,std::condition_variable用于通知工作线程需要完成工作。

如果你真的想要自己实现一个互斥锁,那么请确保你使用的是原子类型,例如std::atomic_flagstd::atomic<bool>等。

在这里实现自己的“线程安全”容器对于你的问题来说是一个简单的选择,它会像(尚未测试,只是为了寻找):

#include <mutex>
#include <utility>
#include <unordered_map>

template <class Value, class Key>
class Container {
 public:
  bool Get(const Key &key, Value &value) {
    std::lock_guard<std::mutex> guard(mtx_);
    auto ite = mp_.find(key);
    if (ite == mp_.end())
      return false;

    value = std::move(ite->second);
    mp_.erase(ite);
    return true;
  }

  template <class ValueType>
  void Insert(const Key &key, ValueType &&value) {
    std::lock_guard<std::mutex> guard(mtx_);
    mp_[key] = std::forward<ValueType>(value);
  }
private:
  std::unordered_map<Value, Key> mp_; 
  std::mutex mtx_;
};

在实现并发算法时你需要注意很多事情,我建议你先阅读一些关于这个主题的书(不要担心,无论如何你都会学到很多东西)。 “行动中的C ++并发”是一个良好的开端。