2016-08-29 4 views
4

В приведенном ниже примере C99 установлен флаг buffer_full (даже при включенной оптимизации -O2) после того, как буфер будет считан или записан на? Или мне нужен барьер памяти, чтобы обеспечить правильный порядок?Нужен ли мне барьер памяти?

Я ожидаю, что это будет запущено на системе, где выровненные 32-битные чтения и записи являются атомарными.

Предположим, что выполняется только один экземпляр каждого потока, и ни один другой поток не обращается к buffer или buffer_full.

char buffer[100]; 
int buffer_full; 

// write interesting data to the buffer. does not read. 
void fill_buffer(char* buffer, size_t buffsz); 
// read the interesting data in the buffer. does not write. 
void use_buffer(const char* buffer, size_t buffsz); 

void writer_thread() 
{ 
    if (!buffer_full) { 
     fill_buffer(buffer, sizeof(buffer)); 
     // is a memory barrier needed here? 
     buffer_full = 1; 
    } 
} 

void reader_thread() 
{ 
    if (buffer_full) { 
     use_buffer(buffer, sizeof(buffer)); 
     // is a memory barrier needed here? 
     buffer_full = 0; 
    } 
} 
+0

Ваш вопрос немного сложно понять, но я полагаю, вы имеете в виду, что * есть доступ к 'buffer_full' atomic *? В принципе, это так. –

+0

Я думаю, что это также зависит от платформы. Если 'int' является native, является атомарным, а до переменной имеет неприсоединившийся адрес. – LPs

+0

Вид. Я хочу, чтобы пустой буфер никогда не читался, и полный буфер никогда не записывался. В основном я занимаюсь заказом. Будет ли настройка buffer_full когда-либо переупорядочена до того, как она будет показана в коде либо компилятором, либо аппаратным обеспечением. – PaulH

ответ

3

Я интерпретирую вас спросить, может ли компилятор изменить порядок назначения на buffer_full с вызовами fill_buffer() и read_buffer(). Такая оптимизация (и любая оптимизация) разрешена только в том случае, если она не изменяет внешне наблюдаемое поведение программы.

В этом случае, поскольку buffer_full имеет внешнюю связь, маловероятно, что компилятор может быть уверен в разрешении оптимизации. Это может быть сделано, если определения функций fill_buffer() и use_buffer() и каждой функции, которую они сами называют, и т. Д.. находятся в одной единице перевода с функциями writer_thread() и reader_thread(), но это в некоторой степени зависит от их реализации. Если соответствующий компилятор не уверен, что оптимизация разрешена, он не должен его выполнять.

Поскольку ваше именование означает, что эти две функции будут работать в разных потоках, однако, то без действий синхронизации, таких как барьер памяти, вы не можете быть уверены в относительном порядке, в котором один поток будет воспринимать изменений в общих , non _Atomic, non volatile данные, выполняемые другой лентой.

Кроме того, если один поток записывает неатомную переменную, а другой поток обращается к той же самой переменной (чтение или запись), тогда существует гонка данных, если только действие синхронизации или атомная операция не вмешивается между ними во всех возможных общих Порядок операций. volatile переменные здесь действительно не помогают (см. Why is volatile not considered useful in multithreaded C or C++ programming?). Однако если вы сделаете buffer_full атомом, или если вы реализуете свои функции с помощью атомных операций чтения и записи на нем, это будет способствовать предотвращению расследований данных, включающих не только эту переменную, но и buffer (для вашей существующей структуры кода).

+0

Спасибо! Будет ли это иметь значение, если буфер или флаг являются атомарными? – PaulH

+0

Редактирование: реализовано Я сказал «атомный», когда я хотел сказать «volatile» в последнем комментарии. – PaulH

+0

Я добавил предположение, что это только 2 потока, которые обращаются к «buffer» и «buffer_full». Учитывая это, требуется ли еще мьютекс? Если да, можете ли вы помочь мне понять, почему? – PaulH

Смежные вопросы