1
votes

I have a shared_ptr stored in a central place which can be accessed by multiple threads through a method getPointer(). I want to make sure that only one thread uses the pointer at one time. Thus, whenever a thread wants to get the pointer I test if the central copy is the only one via std::shared_ptr::unique() method. If it returns yes, I return the copy assuming that unique()==false as long as that thread works on the copy. Other threads trying to access the pointer at the same time receive a nullptr and have to try again in the future.

Now my question:

Is it theoretically possible that two different threads calling getPointer() can get mutual access to the pointer despite the mutex guard and the testing via unique() ?

std::shared_ptr<int> myPointer; // my pointer is initialized somewhere else but before the first call to getPointer()
std::mutex myMutex;

std::shared_ptr<int> getPointer()
{
    std::lock_guard<std::mutex> guard(myMutex);
    std::shared_ptr<int> returnValue;

    if ( myPointer.unique() )
        returnValue = myPointer;
    else
        returnValue = nullptr;

    return returnValue;
}

Regards

2
The linked question does not cover std::shared_ptr::unique and very little about mutexes. It also doesn't explicitly discuss the scenario I listed here, especially the scope problematic. Please remove the duplicate mark. Regards. - Desperado17
I cannot provide the original code because it is confident. The code presented is basically the original code stripped of everything that distracts from the problem or is private. - Desperado17
Then modify your question to ask about the code provided instead of referring to some nebulous unprovided code. - xaxxon
std::shared_ptr::unique is deprecated in C++17 and removed in C++20. I'd suggest avoiding its use. - Jesper Juhl
@xaxxon yes, but only because the temporary return value is immediately destroyed after the first call so the reference count of myMutex returns to 1 I presume? - Desperado17

2 Answers

2
votes

Only one "active" copy can exist at a time.

It is protected by the mutex until after a second shared_ptr is created at which point a subsequent call (once it gets the mutex after the first call has exited) will fail the unique test until the initial caller's returned shared_ptr is destroyed.

As noted in the comments, unique is going away in c++20, but you can test use_count == 1 instead, as that is what unique does.

-1
votes

Your solution seems overly complicated. It exploits the internal workings of the shared pointer to deduce a flag value. Why not just make the flag explicit?

std::shared_ptr<int> myPointer;
std::mutex myMutex;
bool myPointerIsInUse = false;

bool GetPermissionToUseMyPointer() {
    std::lock_guard<std::mutex guard(myMutex);
    auto r = (! myPointerIsInUse);
    myPointerIsInUse ||= myPointerIsInUse;
    return r;
}

bool RelinquishPermissionToUseMyPointer() {
    std::lock_guard<std::mutex guard(myMutex);
    myPointerIsInUse = false;
}

P.S., If you wrap that in a class with a few extra bells and whistles, it'll start to look a lot like a semaphore.