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 байта.

Итак, мои вопросы:

  1. Является ли InterlockedExchange действительно независимым от выравнивания или это выпущено в документации?
  2. Можете ли вы подтвердить, что не буквально параметры, но адрес за длинной * должен быть выровнен на 4 байта (я не могу предположить, как другие параметры не могли быть выровнены на 4 байта, потому что они являются переменными стека)?
  3. Если ответ на вопрос 2 - да: как это можно решить? Изменение выравнивания окружающего класса не вариант, ни атомарный C++ 11, ни ускорение (все из-за корпоративных ограничений и требуемой компиляции для msvc10 в msvc14).

Я решил объявить m_MyMember изменчивым и использовать критические разделы для доступа к нему. Хотя мне бы хотелось, чтобы лучше было правильно объявлять m_MyMember для выравнивания по мере необходимости, потому что эти функции доступа с блокированными переменными расположены вокруг заданной базы кода, и я бы не хотел добавлять дополнительный CS-компонент к каждой переменной.

1 ответ

Ограничение на самом деле не от Microsoft, а от аппаратного обеспечения. Чтобы атомарно изменить материал, он должен быть выровнен (указатель).

Это также верно для членов критического раздела или STD::atomic

Без выравнивания класса, если вы можете из interlock переменная, чтобы гарантировать 4-байтовое выравнивание с классом, тогда это должно работать

Другие вопросы по тегам