std::call_once QNX 延迟初始化问题

std::call_once lazy initialization issue on QNX

我的代码在 QNX 上定期崩溃。它因错误而崩溃

error reading variable: Cannot access memory at address 0x85dd6ac)

同时尝试访问 0x85dd6ac 对象的 std::map 成员变量,该对象使用 std::call_once 延迟初始化。

使用以下伪代码完成初始化:

mutable std::aligned_storage<sizeof(A), alignof(A) >::type m_value;

void init(A *ptr)
{
    new (ptr) A();
}

inline T* data() const
{
    return reinterpret_cast<A*>(&m_value);
}

const A& get() const
{
    std::call_once(m_once_flag, init, data());
    return *data();
}

在某些时候,当访问 get() 返回的对象时,进程崩溃。

在其他平台上问题没有重现,调试起来非常困难。 从代码中我可以看到对象不能取消初始化,此时也不能删除它。

我怀疑 std::call_once 线程安全或内存排序的实现可能存在问题。 有没有人有在 QNX 平台上使用 std::call_once 的经验或类似的错误? 有什么办法可以找到问题吗?

问题出在 std::call_once。这是实施中的错误。 临时替换为 mutex 解决了这个问题。 没有更多时间深入研究细节,但希望这些信息能帮助遇到类似问题的人。

感谢大家的评论!

我在 QNX 中使用 std::call_once 时也有同样的经历,但除了崩溃之外,它还会导致多线程应用程序中的死锁。我建议使用以下模式替换 std::call_once:

static std::atomic< bool > once_flag = false;
if ( !once_flag.exchange( true ) )
{
    // This part will be executed only once.
    // ...
}

更新 根据fefe的评论,该解决方案不满足被动执行的阻塞条件(详见http://www.cplusplus.com/reference/mutex/call_once/)。

如果你也必须满足这一点,你应该实施更复杂的解决方案。这是一个例子:

static std::atomic< bool > once_flag = false;
static std::atomic< bool > once_call_done = false;
if ( !once_flag.exchange( true ) )
{
    // This part will be executed only once.
    // ...

    once_call_done = true;
}
else
{
    // Block until the call once part is running.
    while( !once_call_done )
    {
        sleep( 1 );
    }
}