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

时间:2016-03-22 14:53:04

标签: c++ multithreading c++11 lazy-initialization qnx

我的代码会在QNX上定期崩溃。它崩溃了,错误

  

错误读取变量:无法访问地址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的经验或者那样的bug? 我有什么想法可以找到这个问题吗?

2 个答案:

答案 0 :(得分:1)

问题出在std :: call_once上。这是实施中的错误。 用互斥锁临时替换解决了这个问题。 没有时间深入挖掘细节,但希望这些信息可以帮助那些有类似问题的人。

感谢大家的评论!

答案 1 :(得分:1)

我在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 );
    }
}