jeudi 16 juillet 2015

how to avoid non-deterministic read caused by concurrent write

Non-deterministic read caused by concurrent write can be demonstrated by the following code:

class Bar {
  int val_;
  std::mutex m_;
 public:
  explicit Bar(int v) : val_(v) {}

  int val() {
    std::lock_guard<std::mutex> l(m_);
    return val_;
  }

  void set(int v) {
    std::lock_guard<std::mutex> l(m_);
    val_ = v;
  }
};


class Foo {
  Bar* bar_;
 public:
  explicit Foo(Bar* bar) : bar_(bar) {}
  int val() const { return bar_.val(); }
};

Bar bar(1);
Foo foo(&bar);
cout << foo.val() << endl;  // 1
bar.set(2);  // probably executed in another thread
cout << foo.val() << endl;  // 2

I am interested to know what are the design patterns / coding practices to avoid such problem.

One solution I can think of is to make a "deep copy", i.e. Foo will have a consistent snapshot of data it depends on, so all reads will get the same result. If Foo owns Bar, we can make Bar ref counted, and let Foo maintain a list of different versions of Bar (all mutation to Bar go through Foo), and client only get a "snapshot view" of Foo which only have access to one version of Bar, i.e. a consistent view. However, if Foo does not own Bar, it becomes a mess and I cannot think of a good solution here.

Aucun commentaire:

Enregistrer un commentaire