Состояние гонки: один поток создает статический объект, другой поток использует его до завершения инициализации. Как справиться?

В моем коде есть несколько мест, где статический объект функции создается один раз, а затем используется (копируется) при каждом вызове этой функции. Одна из этих функций может быть вызвана из любого потока. Функция не имеет доступа ни к какому общему состоянию, кроме этого статического объекта.

Когда поток 1 вызывает функцию в первый раз, объект создается и инициализируется. Однако (по счастливой случайности) у меня есть повторяющийся случай, когда программа переключается на поток 2 и вызывает ту же функцию до завершения инициализации. Объект назначен и используется с неверными данными!

Я не знаю, как с этим справиться. Я использую критические секции в коде инициализации, но проблема даже не в этом. Этот объект используется до инициализации в первую очередь.

Я попытался сделать этот поток локальным, используя __declspec(thread), но, по-видимому, это не работает для объектов.

Я мог бы просто окружить все это критическим разделом, и, возможно, это лучшее решение, но меня беспокоят подобные проблемы, возникающие в других частях кода — было бы неплохо иметь общее решение.


person Raptormeat    schedule 27.07.2012    source источник
comment
Однажды я столкнулся с подобной проблемой после перехода с MSVC на Intel. Наше решение состояло в том, чтобы по возможности удалить статические элементы, а во всех остальных случаях гарантировать, что первый доступ к функции, содержащей статическую переменную, заключен в критическую секцию. Обратите внимание: недостаточно, чтобы конструктор переменной был статическим, но доступ к функции, который приводит к инициализации переменной, должен быть атомарным. Очевидно, это приводит к определенному запаху кода, поскольку вы должны убедиться, что каждый первый вызов функции является атомарным...   -  person MFH    schedule 28.07.2012


Ответы (2)


Если вы работаете в Windows, вы можете использовать InitOnceExecuteOnce< /а> API. Более подробную информацию можно найти в этом Рэймонде Чене. почта. Также обратите внимание на более общий std::call_once.

person ThirdOne    schedule 27.07.2012
comment
Эта штука на самом деле стандартная и называется std::call_once - person Stephan Dollberg; 28.07.2012
comment
Спасибо, @bamboon добавил это к моему ответу. - person ThirdOne; 28.07.2012

Не могли бы вы использовать семафор для объекта, установив для семафора уже установленное значение 1 при создании объекта, а затем уменьшив его до нуля, когда объект инициализируется (и готов к использованию).

Просто нужно следить за нехваткой ресурсов.

person John Mitchell    schedule 27.07.2012