简体   繁体   中英

C++ Thread Safe Lazy Load

I have a property which is similar to the following:

private:
Foo* myFoo_m;

public:
Foo getMyFoo() const
{
    if (myFoo_m == NULL)
    {
       myFoo_m = new Foo();
       // perform initialization

This works well in a single-threaded environment, but how do I handle this in a multi-threaded environment? Most of the info I've found deals with static singletons, but in this case, myFoo is a public instance property.

I am porting this over from C# (where I can use Lazy) and Java (where I can use double check locking), but it doesn't seem that there is a straightforward way to do this in C++. I cannot rely on any external libraries (no BOOST), and this needs to work on windows and linux. I also cannot use C++11.

Any insight would be good. I am new to C++.

If you have access to c++11 you can use std::mutex to lock prevent multiple threads from initializing the lazy section. (Note: std::mutex only became available on Windows with VS2012)

You can even perform a scoped aquisition of the mutex with std::lock_guard :

private:

std::mutex m_init_mutex;

public:

Foo getMyFoo() const
{
    {
       std::lock_guard<std::mutex> lock(m_init_mutex);
       if (myFoo_m == NULL)
       {
          myFoo_m = new Foo();
          // perform initialization
       }
    }

EDIT : The OPs now stated that C++11 isn't an option, but perhaps this answer will be useful in the future

By saying "no C++11", "no Boost or other third-party code", "must work on Windows and Linux", you have restricted yourself to using implementation-specific locking mechanisms.

I think your best option is to define a simple lock class for yourself, and implement it to use pthread_mutex on Linux and a CriticalSection on Windows. Possibly you already have some platform-specific code, to start the threads in the first place.

You could try something like Windows Services for UNIX to avoid writing platform-specific code, but it's probably not worth it for one lock. And although it's supplied by Microsoft, you'd probably consider it an external library anyway.

Warning: I didn't see the "no C++11" requirement, so please disregard the answer.


Since C++11 mandates that static variable initialization be thread-safe, here's a simple way that you might consider "cheating":

Foo init_foo()
{
    // initialize and return a Foo
}

Foo & get_instance_lazily()
{
    static Foo impl = init_foo();
    return impl;
}

The instance will be initialized the first time that you call get_instance_lazily() , and thread-safely so.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM