boost::shared_ptr<resource> resource_ptr;
boost::mutex resource_mutex;

void test()
{
  if(!resource_ptr) //#1
  {
    boost::lock_guard<boost::mutex> lk(resource_mutex);
    if(!resource_ptr) //#2
    {
      resource_ptr.reset(new resource); //#3
    }
  }
  resource_ptr->do_something();
}

int  main()
{
  boost::thread t1(test);
  boost::thread t2(test);
  t1.join();
  t2.join():
 
  return 0;
}

According to the text book, this kind of codes may cause race condition, but I don't know why?

If t1 thread initialize the resource_ptr(#3) when t2 haven't gotten into #1
then t2 may or may get true at #2
if t2 get true at #2, the resource have already been initialize, so it would not be initialized again
No matter how hard I try, I can't see why "double-checked locking" would cause race condition?

Thank you very much

Recommended Answers

All 2 Replies

> I can't see why "double-checked locking" would cause race condition?

See: http://drdobbs.com/cpp/184405726

This conclusion was true (for C++03) at the time the article was written.

Nothing you do can alter the fundamental problem: You need to be able to specify a constraint on instruction ordering, and your language gives you no way to do it.

The good news is that C++ now gives fine-grained control over memory ordering and sequencing.
See: http://www.justsoftwaresolutions.co.uk/threading/multithreading-in-c++0x-part-6-double-checked-locking.html

For your specific example, the simple solution is to place the initialization in a static variable at block scope.

If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization ....

With footnote: The implementation must not introduce any deadlock around execution of the initializer. - FDIS

See: http://www.devx.com/SpecialReports/Article/38883/1954

Note: with the caveat

If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

Thanks a lot, multi-thread is very complicated, I didn't plan to learn it so early
but I have to handle this skill for now because of my job.

The text book also suggest we should use std::call_once(my compiler do not
support it yet) to initialize those read only resources. What if we choose a
thread_safe smart pointer for this kind of situations?If we make sure the steps
of "new" and "pointing to the shared resource" are guarded, would this problem
could be solved by that too?Would this guarantee we wouldn't have a raw pointer?

ps : studying the links you posted, maybe the problem would be solved if I can understand the contents
of those links.Thanks a lot.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.