如果底层指针过期,std::atomic<std::weak_ptr<>>::compare_exchange_* 是否能保证正常工作?

问题描述 投票:0回答:1

我有一段代码,如果底层弱指针过期,

std::atomic<std::weak_ptr<T>>
的行为不会像我预期的那样:

std::atomic<std::weak_ptr<Widget>> ptrAtomicWidget = ...;

std::shared_ptr<Widget> ptrWidget = ptrAtomicWidget.load().lock();

while (ptrWidget == nullptr)
{
    ptrWidget = std::make_shared<Widget>();
    std::weak_ptr<Widget> ptrExpected; // <--- nullptr
    std::weak_ptr<Widget> ptrDesired = ptrWidget;

    // Problem Version: Causes an infinite loop when ptrExpected is expired
    if (!ptrAtomicWidget.compare_exchange_weak(ptrExpected, ptrDesired))
    {
        ptrWidget = ptrExpected().lock();
    }

    // Potential Repair Version:  *seems* to work (could alternately move declaration of ptrExpected above while loop)
    if (!ptrAtomicWidget.compare_exchange_weak(ptrExpected, ptrDesired)
    &&  ptrExpected.expired()
    &&  !ptrAtomicWidget.compare_exchange_weak(ptrExpected, ptrDesired))
    {
        ptrWidget = ptrExpected().lock();
    }
}

我遇到的问题涉及循环体“潜在修复版本”的“似乎有效”部分。修复需要两个不同的过期的weak_ptr在compare_exchange期间可靠地相互比较相等。

std::weak_ptr
没有相等运算符,因此其文档对此保持沉默。我能找到的关于
std::atomic<>
专业化的文档(例如 CPPReference)都没有描述指针过期时比较交换的行为。我不知道它是否恰好适用于我的特定编译器,或者 C++ 标准是否保证它。有人知道它是否能保证按标准工作吗?

c++ multithreading atomic compare-and-swap weak-ptr
1个回答
0
投票

您误解了弱指针

compare_exchange
何时成功的条件。 根据
atomic<weak_ptr<T>>::compare_exchange_weak
的规范:

效果:如果

p
等价于
expected
,则将
desired
分配给
p
,并且具有与
success
的值对应的同步语义,否则将
p
分配给
expected
并且具有同步语义对应于
failure
的值。

当两个指针等价时很重要,这也有解释:

备注:如果两个

weak_ptr
对象存储相同的指针值并且共享所有权或均为空,则它们是等效的。 弱形式可能会虚假失败。 请参阅[原子.类型.操作]。

初始化为

ptrExpected
nullptr
不存储与
ptrAtomicWidget
相同的指针值,因此第一次尝试比较交换总是会失败。

第二个“解决方法循环”“有效”,因为当第一次比较交换不可避免地失败时,

ptrAtomicWidget
的当前值被加载到
ptrExpected
中,这使得
ptrDesired
可以在第二次尝试时替换它。 对我来说,似乎
&& ptrExpected.expired()
可以被删除,因为只有在
ptrWidget == nullptr
时你才会进入循环,这意味着
ptrAtomicWidget
为空或过期。

© www.soinside.com 2019 - 2024. All rights reserved.