首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何确保写入相同变量线程的两个线程中的两个类安全?

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

Stack Overflow用户
提问于 2017-03-21 14:27:17
回答 2查看 458关注 0票数 0

我有两个类同时运行在两个线程中,比如类A和类BA正在从一些API中收集数据,并将更新后的数据推入unordered-map作为B->m。同时,B使用数据创建自定义类Bar,代码如下所示:

A**:**

代码语言:javascript
复制
if(m.size() > 0){
//mtx.lock();
lock = B->lock;
if(lock == false){
  lock = true;
  B->m = m;     
  lock = false;
}    
m.clear();
//mtx.unlock();
}

B**:**

代码语言:javascript
复制
 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();
    }}

从这里可以看到,我尝试使用名为lock的布尔值手动实现互斥,有时编译时它会完成seg错误,我认为这是因为边缘情况:当我在类B中将lock设置为true时,类A跳过if(lock == false)B正在读取由A更改的数据。我的问题是,如何避免这种情况发生?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-03-21 14:34:59

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

代码语言:javascript
复制
lock = strategy->lock;
if(lock == false){
  lock = true;
  B->m = m;     
  lock = false;
}

可能会变成这样

代码语言:javascript
复制
lock = strategy->lock;
if(lock == false){
  B->m = m;
}

因为单线程结果(这是编译器默认的观点,如果不告诉它的话)是完全相同的。

还有其他可能失败的原因,例如部分对象填充。一般都很复杂。

因此,您必须使用您正在使用的库为您提供的一些同步对象。对于C++11和更高版本,您可以简单地使用性病::互斥

代码语言:javascript
复制
#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
票数 2
EN

Stack Overflow用户

发布于 2017-03-21 14:54:31

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

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

如果您确实希望实现互斥,那么请确保您使用的是原子类型,如std::atomic_flagstd::atomic<bool>等。

在这里实现自己的“线程安全”容器是一个简单的选择,它将类似于(还没有测试,只是为了查看):

代码语言:javascript
复制
#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++并发”是一个良好的开端。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42929919

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档