Следующая реализация от Wikipedia:барьера памяти в реализации одного производителя одного потребителя
volatile unsigned int produceCount = 0, consumeCount = 0;
TokenType buffer[BUFFER_SIZE];
void producer(void) {
while (1) {
while (produceCount - consumeCount == BUFFER_SIZE)
sched_yield(); // buffer is full
buffer[produceCount % BUFFER_SIZE] = produceToken();
// a memory_barrier should go here, see the explanation above
++produceCount;
}
}
void consumer(void) {
while (1) {
while (produceCount - consumeCount == 0)
sched_yield(); // buffer is empty
consumeToken(buffer[consumeCount % BUFFER_SIZE]);
// a memory_barrier should go here, the explanation above still applies
++consumeCount;
}
}
говорит, что барьер памяти должен использоваться между линией, который обращается к буферу и линией, которая обновляет Count
переменная.
Это делается для того, чтобы процессор не переупорядочивал инструкции выше забора вместе с под ним. Переменная Count
не должна увеличиваться до того, как она будет использоваться для индексации в буфер.
Если забор не используется, не будет ли такое переупорядочение нарушать правильность кода? ЦП не должен выполнять приращение Count
, прежде чем он будет использоваться для индексации в буфер. Процессор не заботится о зависимости данных при переупорядочении команд?
Благодаря
@ user3286661: Это означает, что никакой барьер памяти не может сделать код выше четко определенного C++. Это не помогает с ответом, это объясняет, почему предпосылка вашего вопроса ошибочна. – MSalters
@ user3286661 Мы не заботимся о производительности, не так ли? Это почти правильность. (Потому что производительность кода, который вращается на 'sched_yield', будет ужасной.) Это должен быть либо псевдоядерный, либо специфичный для платформы код. Не существует портативного правила для того, как 'volatile' взаимодействует с барьерами памяти и потоками. –
Вопрос о концепции барьеров памяти. Мы не заботимся о производительности. – user3286661