互斥体可以确保对象的线程可见性,而不是明确地保护它们吗?

时间:2016-02-01 10:31:33

标签: c++ multithreading

考虑下面的代码,线程是否有可能以不同的方式看到对象的状态,尽管它们都用相同的指针引用?

using namespace std;

class ProducerAndConsumer{

  class DummyObject {
  public:
    DummyObject() {
      sprintf(a, "%d", rand());
    }
  private:
    char a[1000];
  };

  mutex queue_mutex_;
  queue<DummyObject *> queue_;
  thread *t1, *t2;

  void Produce() {
    while (true) {
      Sleep(1);
      // constructing object without any explicit synchronization
      DummyObject *dummy = new DummyObject();
      {
        lock_guard<mutex> guard(queue_mutex_);
        if (queue_.size() > 1000) {
          delete dummy;
          continue;
        }
        queue_.push(dummy);
      }
    }
  }

  void Consume() {
    while (true) {
      Sleep(1);
      DummyObject *dummy;
      {
        lock_guard<mutex> guard(queue_mutex_);
        if (queue_.empty())
          continue;
        dummy = queue_.front();
        queue_.pop();
      }
      // Do we have dummy object's visibility issues here?
      delete dummy;
    }
  }

 public:

  ProducerAndConsumer() {
    t1 = new thread(bind(&ProducerAndConsumer::Consume, this));
    t2 = new thread(bind(&ProducerAndConsumer::Produce, this));
  }

};

你能说这个例子是线程安全的吗?互斥是否强制执行缓存废弃?互斥体是否提供了比内存障碍更多的功能以及原子?

1 个答案:

答案 0 :(得分:8)

  

考虑下面的代码,线程可能会以不同的方式看到对象的状态,尽管它们都用相同的指针引用?

答案:没有。

说明:获取互斥锁是一种获取操作,释放它是一种释放操作。

dummy被推入队列时,必须在推送之前进行构造,以便从推送线程的角度保持正确的排序。随后发布的互斥锁将确保发出一个fence,以使其他线程可以看到队列的内容(以及您在此之前修改的所有其他数据)。

类似地,在使用者线程中,从该线程的角度来看,将从队列中对dummy的赋值顺序进行正确排序。获取互斥锁将确保DummyObject中的内存有效。

支持引用§1.10.7:

  

没有相关内存位置的同步操作是围栏,可以是获取围栏,释放围栏,也可以是获取和释放围栏。

...

  

例如,获取互斥锁的呼叫将对包含互斥锁的位置执行获取操作。相应地,释放相同互斥锁的调用将在这些相同位置执行释放操作。