【问题标题】:Can mutexes ensure thread visibility of objects while not explicitly protecting them?互斥锁能否确保对象的线程可见性而不显式保护它们?
【发布时间】:2016-02-01 10:31:32
【问题描述】:

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

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));
  }

};

你能说这个例子是线程安全的吗?互斥锁是否强制缓存垃圾?互斥体是否提供了比内存屏障和原子更多的功能?

【问题讨论】:

  • 与问题无关,但如果队列饱和(包含 1001 个对象),您将泄漏虚拟对象。现代 C++ 中推荐的方法是 std::unique_ptr&lt;&gt;,但在 continue 之前使用简单的 delete 即可。
  • @dan-allen,我的错,谢谢你注意到这一点)

标签: c++ multithreading


【解决方案1】:

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

答案:没有。

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

dummy 被推入队列时,必须在推入之前进行构造,以便从推入线程的角度保持正确的顺序。随后发布的互斥锁将确保发出栅栏以使队列的内容(以及在此之前更改的所有其他数据)对其他线程可见。

类似地,在消费者线程中,从该线程的角度来看,从队列中分配给 dummy 的顺序将被正确排序。获取互斥体将保证DummyObject中的内存有效。

来自 §1.10.7 的支持引用:

没有关联内存位置的同步操作是栅栏,可以是获取栅栏、释放栅栏,或者同时是获取和释放栅栏。

...

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

【讨论】:

  • 回答问题的哪一部分是“否”? (赞成,因为我同意答案,但“否”不清楚,如果读作对错误问题的回答,可能会使 OP 混淆)。
  • @JonathanWakely 谢谢。更新了答案以使其更加清晰。
猜你喜欢
  • 1970-01-01
  • 2011-03-13
  • 2012-07-21
  • 2015-05-03
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多