std::shared_ptr::unique(),复制和线程安全

std::shared_ptr::unique(), copying and thread safety

我有一个 shared_ptr 存储在一个中央位置,多个线程可以通过方法 getPointer() 访问它。我想确保一次只有一个线程使用指针。因此,每当线程想要获取指针时,我都会通过 std::shared_ptr::unique() 方法测试中央副本是否是唯一的。如果它 return 是,我 return 副本假设 unique()==false 只要该线程在副本上工作。其他试图同时访问该指针的线程收到一个 nullptr,以后必须重试。

现在我的问题是:

尽管有互斥保护和通过 unique() 进行的测试,但两个调用 getPointer() 的不同线程在理论上是否可以相互访问指针?

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;
}

此致

一次只能存在一个 "active" 副本。

它受互斥锁保护,直到创建第二个 shared_ptr,此时后续调用(一旦它在第一个调用退出后获得互斥锁)将无法通过 unique 测试直到初始调用者返回的 shared_ptr 被销毁。

如评论中所述,unique 将在 c++20 中消失,但您可以测试 use_count == 1,因为这就是 unique 所做的。

您的解决方案似乎过于复杂。它利用共享指针的内部工作原理来推断标志值。为什么不直接明确标记?

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., 如果你把它包装在 class 中,加上一些额外的花里胡哨,它会开始看起来很像 semaphore.