1

There is a sample code which "works" in a multithreading environment:

void CSampleClass::Stop(void) {
  if (m_pDB != nullptr) {
  ... Here is some code
    m_pDB->Interrupt();
  }
}
, where the m_pDB member is declared as boost::shared_ptr<CSampleDatabase> m_pDB;. m_pDB can be reset in another class method. That is why it is tested to not nullptr. As the code have multiple threads, can be a situation when m_pDB is reset, by another thread, in between if (...) and m_pDB->Interrupt();. The result is quite dramatic. To prevent such situation I use the following code modification
void CSampleClass::Stop(void) {
  auto pDb = m_pDB; //lock
  if (pDb != nullptr) {
  ... Here is some code
    pDb->Interrupt();
  }
}
, i.e. if m_pDB.reset(); called, the object is never released until pDb is destroyed.

The questions are:

  1. Is there a "standard" way to prevent the situation without involving lockers, mutexes, critical sections, etc.? Something like using boost::weak_ptr to break circular references.

  2. Is it guaranteed that the compiler declares pDB as boost::shared_ptr<CSampleDatabase> and not CSampleDatabase *? May be it is safer to write decltype(m_pDB) pDb = m_pDB; //lock?

5
  • 2
    The second version still contains a race condition. Copy-constructing a shared_ptr is not an atomic operation. Commented Mar 24, 2012 at 8:28
  • @n.m.: From here: "shared_ptr objects offer the same level of thread safety as built-in types". This means that it is safe to have multiple shared_ptr instances referring to the same object and to modify those shared_ptrs concurrently, but it is not safe to concurrently modify/read a single shared_ptr instance. Commented Mar 24, 2012 at 9:05
  • @Mankarse, read examples bellow. Case like in topic mentioned there and marked as safe Commented Mar 24, 2012 at 9:15
  • @Lol4t0 You must be reading a different page than I am. This example is mentioned there (example 4) and it reads: "// writes p3; undefined, simultaneous read/write" Commented Mar 24, 2012 at 9:19
  • @R.MartinhoFernandes, yeah, missed that point Commented Mar 24, 2012 at 9:28

1 Answer 1

2

The solution presented is not safe. It is similar to this example from the documentation:

// thread A
p = p3; // reads p3, writes p

// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write

Simultaneous reads from the same instance are safe. Any other concurrent operations on the same instance are not.

Is there a "standard" way to prevent the situation without involving lockers, mutexes, critical sections, etc.? Something like using boost::weak_ptr to break circular references.

You need mutual exclusion, so you need to use a mutual exclusion construct.

Is it guaranteed that the compiler declares pDB as boost::shared_ptr<CSampleDatabase> and not CSampleDatabase *? May be it is safer to write decltype(m_pDB) pDb = m_pDB; //lock?

Yes, pDB will be a shared_ptr.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.