InterlockedCompareExchange - каковы точные требования к выравниванию и как их можно применять?
У меня возникают проблемы с пониманием значения документации MSDN для семейства функций Interlocked Variable Access. Я использую InterlockedExchange для установки и InterlockedCompareExchange для получения переменной-члена, которая используется несколькими потоками.
Элемент находится в 1-байтовом упакованном классе:
#pragma pack(1)
class MyClass {
char _;
long m_MyMember;
// ...
}
Таким образом, член установлен
InterlockedExchange(&m_MyMember, 1);
и получил
long value = InterlockedCompareExchange(&m_MyMember, 0, 0);
Документация InterlockedExchange никоим образом не ссылается на выравнивание (Strg + F "align"), но InterlockedCompareExchange делает:
Параметры для этой функции должны быть выровнены по 32-битной границе; в противном случае функция будет непредсказуемо работать в многопроцессорных системах x86 и любых системах, отличных от x86.
Однако, насколько я понимаю, все параметры являются переменными стека, потому что можно переписать приведенный выше вызов
long *ptr = &m_MyMember;
long zero = 0;
long value = InterlockedCompareExchange(ptr, zero, zero);
Итак, у нас есть блочные переменные класса локального автоматического хранения. Все они идеально выровнены на 4 байта независимо от класса m_MyMember. Конечно, я предполагаю, что это неправильно, и это означает, что адрес позади ptr должен быть выровнен на границе 4 байта.
Итак, мои вопросы:
- Является ли InterlockedExchange действительно независимым от выравнивания или это выпущено в документации?
- Можете ли вы подтвердить, что не буквально параметры, но адрес за длинной * должен быть выровнен на 4 байта (я не могу предположить, как другие параметры не могли быть выровнены на 4 байта, потому что они являются переменными стека)?
- Если ответ на вопрос 2 - да: как это можно решить? Изменение выравнивания окружающего класса не вариант, ни атомарный C++ 11, ни ускорение (все из-за корпоративных ограничений и требуемой компиляции для msvc10 в msvc14).
Я решил объявить m_MyMember изменчивым и использовать критические разделы для доступа к нему. Хотя мне бы хотелось, чтобы лучше было правильно объявлять m_MyMember для выравнивания по мере необходимости, потому что эти функции доступа с блокированными переменными расположены вокруг заданной базы кода, и я бы не хотел добавлять дополнительный CS-компонент к каждой переменной.
1 ответ
Ограничение на самом деле не от Microsoft, а от аппаратного обеспечения. Чтобы атомарно изменить материал, он должен быть выровнен (указатель).
Это также верно для членов критического раздела или STD::atomic
Без выравнивания класса, если вы можете из interlock
переменная, чтобы гарантировать 4-байтовое выравнивание с классом, тогда это должно работать