Каков рекомендуемый способ выравнивания памяти в C ++ 11

Я работаю над реализацией кольцевого буфера для одного производителя. У меня есть два требования:

1) Выровняйте один выделенный кучи экземпляр кольцевого буфера в строке кэша.

2) Выровняйте поле в кольцевом буфере по строке кэша (чтобы предотвратить ложное совместное использование).

Мой класс выглядит примерно так:

#define CACHE_LINE_SIZE 64  // To be used later.

template
class RingBuffer {  // This needs to be aligned to a cache line.
public:
  ....

private:
  std::atomic publisher_sequence_ ;
  int64_t cached_consumer_sequence_;
  T* events_;
  std::atomic consumer_sequence_;  // This needs to be aligned to a cache line.

};

Позвольте мне сначала заняться пунктом 1, т.е.выравнивание выделенного экземпляра кучи класса. Есть несколько способов:

1) Используйте C ++ 11alignas(..) спецификатор:

template
class alignas(CACHE_LINE_SIZE) RingBuffer {
public:
  ....

private:
  // All the private fields.

};

2) Использованиеposix_memalign(..) + размещениеnew(..) без изменения определения класса. Это страдает от того, что не зависит от платформы:

 void* buffer;
 if (posix_memalign(&buffer, 64, sizeof(processor::RingBuffer)) != 0) {
   perror("posix_memalign did not work!");
   abort();
 }
 // Use placement new on a cache aligned buffer.
 auto ring_buffer = new(buffer) processor::RingBuffer();

3) Используйте расширение GCC / Clang__attribute__ ((aligned(#)))

template
class RingBuffer {
public:
  ....

private:
  // All the private fields.

} __attribute__ ((aligned(CACHE_LINE_SIZE)));

4) Я пытался использовать стандартизированный C ++ 11aligned_alloc(..) функция вместоposix_memalign(..) но GCC 4.8.1 в Ubuntu 12.04 не смог найти определение вstdlib.h

Все это гарантированно делает одно и то же? Моя цель - выравнивание строк кэша, поэтому любой метод, имеющий некоторые ограничения на выравнивание (скажем, двойное слово), не подойдет. Независимость платформы, которая будет указывать на использование стандартизированныхalignas(..) это вторичная цель.

Мне не ясноalignas(..) а также__attribute__((aligned(#))) иметь некоторый предел, который может быть ниже строки кэша на машине. Я могу'это больше не воспроизводится, но при печати адресов, я думаю, я не всегда получал 64-байтовые выровненные адреса сalignas(..), Напротивposix_memalign(..) казалось, всегда работает. Опять же, я не могу больше это воспроизводить, поэтому, возможно, я ошибся.

Вторая цель состоит в том, чтобывыровнять поле внутри класса / структуры в строку кэша. Я делаю это, чтобы предотвратить ложный обмен. Я пробовал следующие способы:

1) Используйте C ++ 11alignas(..) спецификатор:

template
class RingBuffer {  // This needs to be aligned to a cache line.
  public:
  ...
  private:
    std::atomic publisher_sequence_ ;
    int64_t cached_consumer_sequence_;
    T* events_;
    std::atomic consumer_sequence_ alignas(CACHE_LINE_SIZE);
};

2) Используйте расширение GCC / Clang__attribute__ ((aligned(#)))

template
class RingBuffer {  // This needs to be aligned to a cache line.
  public:
  ...
  private:
    std::atomic publisher_sequence_ ;
    int64_t cached_consumer_sequence_;
    T* events_;
    std::atomic consumer_sequence_ __attribute__ ((aligned (CACHE_LINE_SIZE)));
};

Оба эти метода, кажется, совпадаютconsumer_sequence по адресу 64 байта после начала объекта, так лиconsumer_sequence выравнивается ли кеш, зависит от того, выровнен ли сам объект. Вот мой вопрос - есть ли лучшие способы сделать то же самое?

РЕДАКТИРОВАТЬ: Причина, по которой align_alloc не работал на моей машине, заключалась в том, что я работал на eglibc 2.15 (Ubuntu 12.04). Это работало над более поздней версией eglibc.

ОтСтраница man:The function aligned_alloc() was added to glibc in version 2.16

Это делает его довольно бесполезным для меня, так как я не могу требовать такой недавней версии eglibc / glibc.

Ответы на вопрос(4)

Ваш ответ на вопрос