我的代码会在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?
我有什么想法可以找到这个问题吗?
答案 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 );
}
}