Заполнение строки кэша для переменных, кратных размеру строки кэша

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

// compute cache line padding size
constexpr u64 CLPAD(u64 _objSize) {
  return ((_objSize / CACHELINE_SIZE) * CACHELINE_SIZE) +
      (((_objSize % CACHELINE_SIZE) > 0) * CACHELINE_SIZE) -
      _objSize;
}

alignas(CACHELINE_SIZE) MyObject myObj;
char padding[CLPAD(sizeof(myObj))];

Это прекрасно работает для меня, но я столкнулся с проблемой сегодня, когда я использовал эту методологию для нового типа объекта. Функция CLPAD() возвращает количество символов, необходимое для заполнения типа ввода до следующей строки кэша. Тем не менее, если я добавлю тип, который имеет размер, кратный числу строк кэша, CLPAD вернет 0. Если вы попытаетесь создать массив нулевого размера, вы получите следующее предупреждение / ошибку:

ISO C++ forbids zero-size array 'padding'

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

Как я могу сделать объявление 'padding' исчезающим, если CLPAD возвращает 0?

1 ответ

Решение

Принимая страницу от std::aligned_storage<>Я придумал следующее:

template<class T, bool = false>
struct padded
{
    using type = struct
    {
        alignas(CACHELINE_SIZE)T myObj;
        char padding[CLPAD(sizeof(T))];
    };
};

template<class T>
struct padded<T, true>
{
    using type = struct
    {
        alignas(CACHELINE_SIZE)T myObj;
    };
};

template<class T>
using padded_t = typename padded<T, (sizeof(T) % CACHELINE_SIZE == 0)>::type;

Использование:

struct alignas(32) my_type_1 { char c[32]; }; // char c[32] to silence MSVC warning
struct my_type_2 { char c[CACHELINE_SIZE * 2]; }; // ditto

int main()
{
    padded_t<my_type_1> pt0;
    padded_t<my_type_2> pt1;

    sizeof(pt0);    // 128
    alignof(pt0);   // 128

    sizeof(pt1);    // 256
    alignof(pt1);   // 128
}

Вы можете предоставить функцию для доступа myObj как пожелаешь.

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