Как запретить g++ оптимизировать цикл, управляемый переменной, которую можно изменить с помощью IRQ?

Рассмотрим следующий фрагмент кода:

unsigned global;
while(global);

global изменяется в функции, которая вызывается IRQ. Однако g++ удаляет тест «не ноль» и переводит цикл while в бесконечный цикл.

Отключение оптимизации компилятора решает проблему, но предлагает ли C++ для этого языковую конструкцию?


person 0xbadf00d    schedule 29.02.2012    source источник
comment
@ Styne666: вопрос в названии   -  person Necrolis    schedule 29.02.2012
comment
См. также stackoverflow.com/q/7083482/594137.   -  person Samuel Harmer    schedule 29.02.2012
comment
@ Styne666 Styne666 - не рекомендуется писать код, для работы которого требуется определенная конфигурация компилятора. Таким образом, отключение оптимизации не подходит для производственного кода.   -  person 0xbadf00d    schedule 29.02.2012
comment
@ Styne666: Вы можете удалить свой отрицательный голос. Вопрос был понятен, хотя и не очень хорошо сформулирован. И отключение оптимизаций не является реальным ответом в этом отношении.   -  person Sebastian Mach    schedule 29.02.2012
comment
@ Styne666: Я согласен с тем, что этот вопрос не очень точен и что он уже дал неправильный ответ самому себе, предполагая, что глобальное или частичное отключение оптимизации является единственным решением. Но речь идет не об отключении оптимизации, а о том, чтобы заставить его занятый цикл ожидания работать, для чего предназначен volatile.   -  person Gunther Piez    schedule 29.02.2012
comment
@ Styne666: оригинальное название содержало цикл, а не циклы. Не будь упрямым. Значение имеет то, как звучит вопрос теперь, неважно, кто его изменил, и теперь ваша первоначальная мотивация больше не соответствует действительности. Если ОП решит, что твик не нравится, он имеет право отредактировать его снова, а в правилах SO говорится, что если произошло редактирование, вы можете повторно проголосовать (информация: вам не разрешено повторно отдавать голоса, если только редактирование случилось).   -  person Sebastian Mach    schedule 29.02.2012
comment
Я нашел вопрос вполне ясным. Может быть, это было не идеально сформулировано, но, возможно, английский тоже не является родным языком ОП (и, кроме того, я видел гораздо хуже на SO). OP хочет вращаться в цикле, пока какое-либо прерывание не изменит значение. Не работает при включенных оптимизациях (но работает в неоптимизированной сборке). Очевидно, ОП хотел бы, чтобы это работало в любом случае. Что в этом непонятного или где есть место для интерпретации?   -  person Damon    schedule 29.02.2012
comment
@ Styne666: Я вижу, вы удалили свои сообщения, но ваш голос остается. Что я прочитал в этом поведении, так это то, что я был неправ, но мой голос остается в качестве наказания за то, что вы осмелились критиковать меня. Пожалуйста, поправьте меня, если я ошибаюсь, я признаю любые ошибки на моей стороне. Будьте честны с собой.   -  person Sebastian Mach    schedule 29.02.2012
comment
Я удалил комментарии, так как это стало разговором, не связанным с заданным вопросом. Голосование остается, потому что ОП не отредактировал свой вопрос (в ответ на ответы и комментарии), чтобы уточнить намерение и значение вопроса. Без правок, предоставленных OP (или ответа, помеченного как правильный), никто не может знать, какой ответ правильный.   -  person Samuel Harmer    schedule 29.02.2012


Ответы (3)


Объявите переменную как volatile:

volatile unsigned global;

Это ключевое слово, которое сообщает компилятору, что global можно изменять в разных потоках и для него следует отключить все оптимизации.

person Luchian Grigore    schedule 29.02.2012
comment
Может быть, заменить все оптимизации на определенные оптимизации, так как есть еще много оптимизаций, которые можно применить. Например, в global = 5 + 6; ваше утверждение может подразумевать, что 5 + 6 не уменьшены. - person Sebastian Mach; 29.02.2012
comment
Добавление квалификатора volatile не меняет созданный код операции. Это все равно переводится как бесконечный цикл... - person 0xbadf00d; 29.02.2012
comment
@SaschaHoll да, это так. Вы можете установить global в 0 в другом потоке, и цикл завершится. - person Luchian Grigore; 29.02.2012
comment
@luchian нет, цикл не обязательно остановится, потому что он не определен (гонка данных) - person Johannes Schaub - litb; 29.02.2012
comment
@ Лучиан Григоре - я согласен с тобой. Это должно помешать компилятору оптимизировать цикл, но это не так. Созданный код операции такой же, как и раньше. Проверено на i586-elf-g++ 4.6 - person 0xbadf00d; 29.02.2012
comment
@JohannesSchaub-litb, как бы вы посоветовали ему это сделать? - person Luchian Grigore; 29.02.2012
comment
@луч, как ты и предлагаешь. то, что подход, который вы предлагаете, является правильным, не означает, что все ваши комментарии верны. - person Johannes Schaub - litb; 29.02.2012
comment
@LuchianGrigore Это зависит от его платформы. Портативного IRQ не существует. На типичных платформах с использованием атомарных операций GCC является лучшим решением. - person David Schwartz; 29.02.2012
comment
@JohannesSchaub-litb Если global записывается только в одном потоке, это все еще гонка данных? - person J.N.; 29.02.2012
comment
@jn я не знаю (недостаточно знаком с проблемами потоковой передачи), но я думаю, что это не так. но, как говорит другой парень, спецификация С++ в любом случае ничего не говорит об обработчиках прерываний. - person Johannes Schaub - litb; 29.02.2012
comment
@ JN: Почти никогда не бывает, чтобы обработчик IRQ всегда работал в том же потоке, что и код приложения (во всяком случае, на многозадачных компьютерах общего назначения, возможно, на встроенных контроллерах). Если это код ядра или что-то в этом роде, то все зависит от платформы. - person David Schwartz; 29.02.2012
comment
@DavidSchwartz: мои вопросы были больше похожи на то, что если есть один-единственный поток (будь то прерывание или обычный поток), который записывает переменную, в то время как все остальные читают, это все еще гонка данных? (Я так не думаю, если переменная меньше или равна размеру машинного слова и выровнена). - person J.N.; 29.02.2012
comment
@ JN: Да, это все еще гонка данных. Ничто в стандарте C++ не делает размер слова машины особенным. C++, безусловно, может поддерживать процессоры, которые не могут выполнять атомарную запись или чтение с собственным размером слова. - person David Schwartz; 29.02.2012
comment
@DavidSchwartz, я понял твою точку зрения. Я думаю, что стандарт не должен заморачиваться с такими процессорами ;). Не могли бы вы назвать один для моей культуры? Наконец, я предполагаю, что любой ЦП, по крайней мере, атомарно читает и записывает с некоторым размером, который мы могли бы разумно приблизить к 8 битам, и этого было бы достаточно для хранения логического значения. Я пытаюсь надавить слишком сильно? Большое спасибо за интересное обсуждение. - person J.N.; 29.02.2012
comment
@JN: У нас есть стандарт, который у нас есть. Если вам это не нравится, ваш выбор — не программировать на C++ или принять его. Если вы притворяетесь, что у вас есть гарантии, которых у вас нет, ваше программное обеспечение сломается, когда ваши пользователи обновят свои процессоры, операционные системы, библиотеки и так далее. Это, по крайней мере, в моей книге, совершенно неприемлемо. Не имеет значения, что делают современные платформы, когда вы говорите о том, на что вы можете положиться. - person David Schwartz; 01.03.2012

Поскольку вы используете GCC и говорите, что создание переменной volatile не работает, вы можете обмануть оптимизатор, заставив его думать, что цикл изменяет переменную, солгав компилятору:

while(global)
  asm volatile("" : "+g"(global));

Это оператор встроенного ассемблера, в котором говорится, что он изменяет переменную (она передается как операнд ввода-вывода). Но он пустой, поэтому очевидно, что он ничего не делает во время выполнения. Тем не менее, оптимизатор думает, что изменяет переменную — так сказали программисты, а компилятор, за исключением подстановки операндов (что означает простую замену одного текста другим), на самом деле не заботится о теле встроенного ассемблера и не будет ничего делать. забавные вещи к нему.

И поскольку тело пусто, а ограничение использовало его наиболее общее из доступных, оно должно надежно работать на всех платформах, где GCC поддерживает встроенную сборку.

person Community    schedule 29.02.2012

Вы можете использовать атрибуты GCC в объявлении функции, чтобы отключить оптимизацию для каждой функции:

void myfunc() __attribute__((optimize(0)));

Дополнительную информацию см. на странице атрибутов функций GCC.

person Silas Parker    schedule 29.02.2012
comment
Если переменная должна находиться в определенном разделе памяти, используйте section Атрибут переменной, чтобы разместить его правильно. Вам также может понадобиться пометить его как volatile. - person Silas Parker; 05.03.2012