std :: call_once Ленивая проблема инициализации в QNX

Мой код периодически падает на QNX. Вылетает с ошибкой

ошибка чтения переменной: невозможно получить доступ к памяти по адресу 0x85dd6ac)

при попытке доступа к переменной члена std :: map 0x85dd6ac объект, который лениво инициализируется с помощью 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 реализация с поточной безопасностью или упорядочением памяти.
Кто-нибудь имеет опыт работы с std :: call_once на платформе QNX или такие ошибки?
Любые идеи, как я могу найти проблему?

3

Решение

У меня есть такой же опыт использования std :: call_once в QNX, но помимо сбоя это может вызвать также мертвую блокировку в многопоточном приложении. Я предлагаю использовать следующий шаблон для замены 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 );
}
}
1

Другие решения

Проблема была с std :: call_once. Это ошибка в реализации.
Временная замена мьютексом решила проблему.
У меня не было больше времени, чтобы копаться в деталях, но, надеюсь, эта информация поможет кому-то с подобной проблемой.

Спасибо всем за ваши комментарии!

1

По вопросам рекламы [email protected]