Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это. Да и даже если так, то что тогда произойдет, если pthread_mutex_lock() — inline-функция или макроопределение?
Вообще, судя по http://alenacpp.blogspot.com/2006/04/volatile.html#comment-1976129473176086084 volatile все-таки стоит ставить. В таком случае встречный вопрос — а как быть с GTK в многопоточных приложениях? В отдельном потоке я могу создать виджеты с volatile, вызвать gdk_threads_enter()/gdk_threads_leave(), но GTK-то ничего знать о них не будет...
Здравствуйте, riYu, Вы писали:
Y>Собственно вопрос.
Y>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
В общем таки желательно.
Y>Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это.
Это так. Но вообще-то если Вы про "закэшированное", то связь с функциями lock/unlock тут иная. Не буду сильно вдаваться в подробности, но есть вопрос переупорядочения машинных команд по желанию процессора, и взятие лока должно быть гарантированно отработано до работы с данными, защищёнными этим локом, а освобождение лока — после такой работы. Думаю, Вам вспомнилось что-то из этой области.
Y> Да и даже если так, то что тогда произойдет, если pthread_mutex_lock() — inline-функция или макроопределение?
А какая нафиг разница? pthread_mutex_lock — нечто, что обязано выполнить операцию захвата мьютекса до начала выполнения кода за ним. Точка. Как оно при этом реализовано — вопрос десятый. А вот то, что компилятор в принципе может не знать про то, что в природе есть какие-то нити (треды) — вопрос серьёзный, и volatile — общий метод сказать ему "чувак, тут может вмешаться кто-то посторонний, так что ты не думай, что можешь сэкономить".
Y>Вообще, судя по http://alenacpp.blogspot.com/2006/04/volatile.html#comment-1976129473176086084 volatile все-таки стоит ставить.
Угумс.
Y> В таком случае встречный вопрос — а как быть с GTK в многопоточных приложениях? В отдельном потоке я могу создать виджеты с volatile, вызвать gdk_threads_enter()/gdk_threads_leave(), но GTK-то ничего знать о них не будет...
А в чём специфика ситуации? Расскажите. С GTK не работал.
The God is real, unless declared integer.
Re: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, riYu, Вы писали:
Y>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
Эти средства относятся к разным областям и никак не связаны.
Y>Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это.
Компиляторы гарантируют, что последствия операций будут такими же, как если бы операции выполнились в том порядке, в каком они присутствуют в коде. Если это не так — значит, баг в компиляторе.
Y>Вообще, судя по http://alenacpp.blogspot.com/2006/04/volatile.html#comment-1976129473176086084 volatile все-таки стоит ставить.
Вне остального контекста как-то не совсем понятно. Вполне возможно, что вынос присвоения в том контексте никак не влияет на логику, например, если компилятор знает, что присвоение на данной архитектуре будет атомарно, или других обращений к переменной нет.
Y>В таком случае встречный вопрос — а как быть с GTK в многопоточных приложениях? В отдельном потоке я могу создать виджеты с volatile, вызвать gdk_threads_enter()/gdk_threads_leave(), но GTK-то ничего знать о них не будет...
volatile для переменной — это, грубо говоря, прибивание операций с переменной гвоздями. Будет имееть определенный эффект при синхронизации, но все же синхронизацию принято осуществлять другими методами.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[2]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, ДимДимыч, Вы писали:
ДД>Здравствуйте, riYu, Вы писали:
Y>>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
ДД>Эти средства относятся к разным областям и никак не связаны.
Связаны. Volatile запрещает оптимизацию использования любой переменной в расчёте на участие в её судьбе постороннего агента. Кем этот агент является — сетевой картой, обработчиком прерывания или другой нитью — для компилятора уже неважно. Цитирую стандарт:
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have unknown side effects.
Там дальше ссылка на abstract machine ("в строгом соответствии с ней"), не хочу это приводить, но смысл такой — вне выражения с переменной компилятор обязан потерять всё знание про неё.
Y>>Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это. ДД>Компиляторы гарантируют, что последствия операций будут такими же, как если бы операции выполнились в том порядке, в каком они присутствуют в коде. Если это не так — значит, баг в компиляторе.
Это верное утверждение, но для данного вопроса недостаточное.
ДД>volatile для переменной — это, грубо говоря, прибивание операций с переменной гвоздями. Будет имееть определенный эффект при синхронизации, но все же синхронизацию принято осуществлять другими методами.
А это не метод синхронизации, это обеспечение её корректности.
The God is real, unless declared integer.
Re[2]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, riYu, Вы писали:
Y>>Собственно вопрос.
Y>>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
N>В общем таки желательно.
Здравствуйте, kvser, Вы писали:
Y>>>Собственно вопрос.
Y>>>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
N>>В общем таки желательно.
K>прочитайте ветку
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, kvser, Вы писали:
Y>>>>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
N>>>В общем таки желательно.
K>>прочитайте ветку
Спасибо, кажется, до меня начало доходить...
N>А в чём специфика ситуации? Расскажите. С GTK не работал.
Специфика, на мой взгляд, в том, что в GTK всегда работает поток Main loop, обрабатывающий события от GUI, хотя в то же время я могу вмешиваться в его работу из другого потока, окружив свой код вызовами gdk_threads_enter()/gdk_threads_leave() так, что он об этом даже не узнает. Т. е. получается, что внутри GTK в коде никакие volatile не ставятся, и при оптимизации компилятор может поместить некоторые операции обращения к виджетам, которые я изменяю, перед кодом, который захватывает критическую секцию, которую я отпускаю после изменения данных виджетов функцией gdk_threads_leave().
Прочитал всю ветку — там чуть ли ни у каждого автора своя теория по поводу того, как в действительности надо поступать и почему. К единому мнению, вроде, так и не пришли.
Re[3]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, netch80, Вы писали:
N>Связаны. Volatile запрещает оптимизацию использования любой переменной в расчёте на участие в её судьбе постороннего агента. Кем этот агент является — сетевой картой, обработчиком прерывания или другой нитью — для компилятора уже неважно.
Нам ведь нужно целостность переменной обеспечить, а не запретить оптимизацию. Volatile скажет о том, что при каждой записи в переменную произойдет физическая запись по адресу, где эта переменная находится, а при каждом чтении — физическое чтение по этому адресу. Для обеспечения целостности переменной это не является ни необходимым, ни достаточным условием.
N>Цитирую стандарт:
N>
N>An object that has volatile-qualified type may be modified in ways unknown to the implementation or have unknown side effects.
Да, изменение переменной другой нитью можно назвать частным случаем 'modification in ways unknown to the implementation'.
N>Там дальше ссылка на abstract machine ("в строгом соответствии с ней"), не хочу это приводить, но смысл такой — вне выражения с переменной компилятор обязан потерять всё знание про неё.
Это следствие вышеприведенной цитаты.
Y>>>Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это. ДД>>Компиляторы гарантируют, что последствия операций будут такими же, как если бы операции выполнились в том порядке, в каком они присутствуют в коде. Если это не так — значит, баг в компиляторе.
N>Это верное утверждение, но для данного вопроса недостаточное.
Почему? Можно пример, когда pthread_mutex_lock()/pthread_mutex_unlock() без volatile недостаточно для обеспечения атомарности?
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[3]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Автор комментария так и не сообщил, к чему приводило то, что "оптимизатор выносил присвоение за выход из мьютекса". Возможно, в его контексте это не имело никакого значения, и "необходимость volatile" существует только в его воображении. Я, например, какое-то время назад был очень удивлен, увидев в коде, сгенерированном gcc, помещение аргумента функции в регистр уже после вызова функции, а не до него. Оказалось, так и должно быть: особенность архитектуры
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[5]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, kvser, Вы писали:
K>Это ответ и автору тоже.
K>Я не понял почему-таки желательно?
Потому что в один сильно не прекрасный день компиляторы начнут оптимизировать доступ к переменным без volatile, и большому количеству кода настанет северный пушной песец.
The God is real, unless declared integer.
Re[4]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, ДимДимыч, Вы писали:
N>>Связаны. Volatile запрещает оптимизацию использования любой переменной в расчёте на участие в её судьбе постороннего агента. Кем этот агент является — сетевой картой, обработчиком прерывания или другой нитью — для компилятора уже неважно. ДД>Нам ведь нужно целостность переменной обеспечить, а не запретить оптимизацию. Volatile скажет о том, что при каждой записи в переменную произойдет физическая запись по адресу, где эта переменная находится, а при каждом чтении — физическое чтение по этому адресу. Для обеспечения целостности переменной это не является ни необходимым, ни достаточным условием.
Но если вместе с этим обеспечен запрет от чужого доступа средствами синхронизации, такими, как мьютексы — полученный комплекс средств достаточен. Необходим ли — это более абстрактно-философский вопрос, обсуждать который я не хочу.
ДД>Да, изменение переменной другой нитью можно назвать частным случаем 'modification in ways unknown to the implementation'.
Ну дык ёлы-палы.;)
Y>>>>Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это. ДД>>>Компиляторы гарантируют, что последствия операций будут такими же, как если бы операции выполнились в том порядке, в каком они присутствуют в коде. Если это не так — значит, баг в компиляторе. N>>Это верное утверждение, но для данного вопроса недостаточное. ДД>Почему? Можно пример, когда pthread_mutex_lock()/pthread_mutex_unlock() без volatile недостаточно для обеспечения атомарности?
А при чём тут атомарность? Атомарность-то они обеспечат. А вот отсутствие кэширования — нет.
The God is real, unless declared integer.
Re[5]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, netch80, Вы писали:
N>А при чём тут атомарность? Атомарность-то они обеспечат. А вот отсутствие кэширования — нет.
Разве lock()/unlock() функции не сбрасывают на SMP "личный" кэш процессора во избежание false sharing? Для запрета всего кэширования применяются другой метод — соответствующая настройка MMU, пользовательскому процессу в общем случае недоступный и ненужный.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[6]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, ДимДимыч, Вы писали:
ДД>Здравствуйте, netch80, Вы писали:
N>>А при чём тут атомарность? Атомарность-то они обеспечат. А вот отсутствие кэширования — нет.
ДД>Разве lock()/unlock() функции не сбрасывают на SMP "личный" кэш процессора во избежание false sharing?
1. Не видел ни одной системы, где бы эти функции сбрасывали кэш. Что за безумная идея? Откуда Вы вообще её взяли? Кэш памяти в процессоре — штука достаточно умная, чтобы не требовать общего сброса (безумно дорогого, кстати) на малейший чих.
2. А при чём тут вообще кэширование памяти в процессоре? Весь тред посвящён кэшированию значения переменной компилятором в другом месте (как правило, в регистре). Например, в коде вида
int a, b, c;
b = a;
unlock(m);
lock(m);
c = a;
компилятор может закэшировать a в регистре между её чтениями, или заменить второе присвоение на c=b, или сделать любое другое действие подобного типа. И без volatile ему никто это не запретит.
The God is real, unless declared integer.
Re[7]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, netch80, Вы писали:
N>1. Не видел ни одной системы, где бы эти функции сбрасывали кэш. Что за безумная идея? Откуда Вы вообще её взяли? Кэш памяти в процессоре — штука достаточно умная, чтобы не требовать общего сброса (безумно дорогого, кстати) на малейший чих.
Про общий сброс всех кэшей на малейший чих я не говорил. А проблема false sharing на SMP присутствует (если у каждого ядра есть как минимум один свой кэш), но к данной дискуссии, оказывается, отношения не имеет
N>2. А при чём тут вообще кэширование памяти в процессоре?
Вот и я думаю — при чем здесь кэширование в процессоре?
N>Весь тред посвящён кэшированию значения переменной компилятором в другом месте (как правило, в регистре). Например, в коде вида
N>
N> int a, b, c;
N> b = a;
N> unlock(m);
N> lock(m);
N> c = a;
N>
N>компилятор может закэшировать a в регистре между её чтениями, или заменить второе присвоение на c=b, или сделать любое другое действие подобного типа. И без volatile ему никто это не запретит.
Для ядра пишут вот что: http://kernel.org/doc/Documentation/volatile-considered-harmful.txt. Уверен, что в userspace ситуация не сильно отличается. Если же все-таки существуют какие-нибудь более-менее официальные рекомендации по использованию volatile для защиты данных в мультинитевых приложениях, а не только домыслы анонимных комментаторов, буду благодарен за ссылки.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[8]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, ДимДимыч, Вы писали:
N>>компилятор может закэшировать a в регистре между её чтениями, или заменить второе присвоение на c=b, или сделать любое другое действие подобного типа. И без volatile ему никто это не запретит. ДД>Для ядра пишут вот что: http://kernel.org/doc/Documentation/volatile-considered-harmful.txt.
Спасибо, отличный пример бреда сивой кобылы в лунную ночь. "Volatile плохо, потому что не позволяет разумную оптимизацию". То, что если оно позволит разумную — позволит и неразумную, тут не вспоминается, и никакие down(), mutex_lock() и прочие этому не помешают — если компилятор туп, то он однородно и равномерно туп. Именно это и происходит с GCC.
И в этой статье "забыли" упомянуть то, как оно реально в Linux лечится. А лечится — разделением на функции, между которыми оптимизация доступа к переменной уже не производится.
В случае нормального компилятора и современной обстановки, когда volatile действительно относится не только к неуправляемым внешним источникам модификации (как другие устройства), но и к управляемым (к этому относится ситуация, когда за счёт мьютекса можно безбоязненно доступаться к переменным, пока он захвачен) — решением стала бы явная директива "барьера" оптимизации доступа к переменным (включённая в реализацию локов).
ДД> Уверен, что в userspace ситуация не сильно отличается. Если же все-таки существуют какие-нибудь более-менее официальные рекомендации по использованию volatile для защиты данных в мультинитевых приложениях, а не только домыслы анонимных комментаторов, буду благодарен за ссылки.
Я такого не видел, но я работаю только с GCC, для которого достаточно (AFAIR) вызова функции.
The God is real, unless declared integer.
Re[9]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, netch80, Вы писали:
N>Спасибо, отличный пример бреда сивой кобылы в лунную ночь. "Volatile плохо, потому что не позволяет разумную оптимизацию".
Короче, все понятно Вести дальнейшую дискуссию считаю нецелесообразным.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[10]: volatile - нужен ли при pthread_mutex_lock() и в GTK
Здравствуйте, ДимДимыч, Вы писали:
ДД>Здравствуйте, netch80, Вы писали:
N>>Спасибо, отличный пример бреда сивой кобылы в лунную ночь. "Volatile плохо, потому что не позволяет разумную оптимизацию".
ДД>Короче, все понятно :down: Вести дальнейшую дискуссию считаю нецелесообразным.
Up to you. Залагаться на линуксовую документацию при том, какой "дефолт" вызвала всего лишь попытка перейти на GCC 4.4 — действительно, тут дискутировать уже не о чем.
The God is real, unless declared integer.
Re[4]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, ДимДимыч, Вы писали:
ДД>Почему? Можно пример, когда pthread_mutex_lock()/pthread_mutex_unlock() без volatile недостаточно для обеспечения атомарности?
например:
#include <pthread.h>
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static int acquires_count = 0;
int
trylock()
{
int res;
res = pthread_mutex_trylock(&mutex);
if (res == 0)
++acquires_count;
return res;
}
Здравствуйте, ДимДимыч, Вы писали:
N>>какой "дефолт" вызвала всего лишь попытка перейти на GCC 4.4 ДД>Так GCC 4.4 уже под GPLv3 идет, разве не этот факт вызвал "дефолт"?
Нет, речь о другом. Linux ломается с каждой новой версией, потому что что-то в мелочах меняется (чаще всего стили оптимизации), но в случае 4.4 количество поломок было особенно крупным.
Я разверну мысль из предыдущих сообщений. Отсутствие volatile склоняет компилятор к возможности оптимизировать доступ к переменной его кэшированием (прочитать или записать меньшее количество раз, чем надо), но есть чёткие границы, через которые он не переходит. Это границы тел функций (не в случае инлайнинга) и границы — вызовы функций, но второе — только если он гарантированно не может сам понять, что происходит в этой функции.
Представим себе систему с кооперативной многозадачностью, когда запрет переключения реализуется глобальной переменной. Если установка и снятие такого "лока" сделано напрямую в функции, то компилятор вполне вероятно захочет это оптимизировать. Это код следующего вида:
extern volatile nosched;
...
foo = 1;
nosched = 0; // разрешили переключение
*bar = 1; // что-то снаружи стронули и возможно нам дали другие данные
nosched = 1; // запретили переключение - работаем с даннымиif (foo != 3) {
...
}
тут компилятор захочет оптимизировать и наверняка это сделает — именно foo ничем не защищено против этого.
Главное здесь — чтобы компилятор при сборке данного модуля _не знал_, что такое эти lock_scheduler() и unlock_scheduler(), или для них была явная метка "что-то меняют, а что — ХЗ" (как в asm volatile). Тогда компилятор остережётся кэшировать foo — он не знает, менялось оно в этих вызовах или нет. Незнание реализуется ссылкой на другой модуль и его отделённой компиляцией.
(UPDATE: ещё штатный метод для gcc:
asm volatile("":::"memory")
— явное указание, что встраиваемый код изменил содержимое памяти и нельзя через его границу оптимизировать доступ. Должны быть аналоги для других компиляторов.)
Именно это и является той защитой, которая не позволяет коду в Linux сходить с ума и которая работает и против gcc, и вообще против любого нормального компилятора. И, как видим, в том тексте про это — ни слова. Есть, однако, одна фраза про "it acts as a memory barrier", но она неоднозначна: понятие memory barrier давно закреплено за другим явлением — средствами предотвращения нежелательного переупорядочения операций процессора. И при этом не сказано, что защитой против оптимизации компилятором является любая функция неизвестного компилятору смысла, а не только функции работы с семафорами и спинлоками (хотя именно эти содержат полный комплект необходимых защит, не только против компиляторной оптимизации).
Ну а почему я это связал с версией gcc — потому что качество кода и качество документации тут примерно одинаково по сути, а именно — резко неровно. Рядом с идеальным результатом может находиться кусок гнилого бреда. На что собственно и нарвались в обоих случаях.
Здравствуйте, netch80, Вы писали:
N>Фух... надеюсь, теперь понятно.
Техническая сторона вопроса и раньше была понятна, я не отрицаю существования такой проблемы, но считаю, что метод ее решения — использование volatile — в общем случае неприемлим, и применять его "на всякий случай" неправильно.
Оптимизация, производимая компилятором — вторична, программиста не должно заботить, где находятся промежуточные результаты вычислений: в памяти ли или в регистрах. Нити одного процесса по определению выполняются в одном адресном пространстве, поэтому если первая нить выполняет:
...
foo = 1;
unlock();
а вторая:
lock();
use(foo);
...
и lock()/unlock() предназначены для синхронизации, то
1) use(foo) не должен выполниться ранее, чем отработает unlock()
2) foo должна содержать корректное значение, присвоенное перед unlock().
Иначе теряется смысл как нитевой модели, так и присвоения значений переменным вцелом.
И как работать в мультинитевой среде с более сложными структурами данных? Представляешь, во что выльется объявление volatile A в чем-то типа:
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, riYu, Вы писали:
Y>>Собственно вопрос.
Y>>Если при доступе к переменной я окружаю код вызовами pthread_mutex_lock()/pthread_mutex_unlock(), то нужно ли при ее объявлении использовать квалификатор volatile?
N>В общем таки желательно.
Должен внести уточнение. При правильной реализации данных функций работы с мьютексом — не нужно. Собственно это всё рассказано в продолжении треда, но акцент тут надо поставить на реализации. Мне приходилось сталкиваться и с такими, где надо было это подпирать. Сейчас вроде бы в большинстве реализаций этой проблемы уже нет.
Собственно я "вспомнил" опыт с такими странными средами и поэтому взвился. В корректной реализации есть таки адекватные защиты и можно не бояться.
Y>>Где-то слышал, что компиляторы гарантируют, что после вызова функции в регистрах не окажется закэшированного значения переменной, но не уверен, так ли это. N>Это так. Но вообще-то если Вы про "закэшированное", то связь с функциями lock/unlock тут иная. Не буду сильно вдаваться в подробности, но есть вопрос переупорядочения машинных команд по желанию процессора, и взятие лока должно быть гарантированно отработано до работы с данными, защищёнными этим локом, а освобождение лока — после такой работы. Думаю, Вам вспомнилось что-то из этой области.
Аналогично предыдущему. Вызов внешней функции влияет на компилятор, а её реализация — на процессор, если это ему явно нужно указывать.
Y>> Да и даже если так, то что тогда произойдет, если pthread_mutex_lock() — inline-функция или макроопределение? N>А какая нафиг разница? pthread_mutex_lock — нечто, что обязано выполнить операцию захвата мьютекса до начала выполнения кода за ним.
И разница таки есть, в случае макроопределения и прочих вариантов требуется какой-то иной метод поставить компилятору барьер кэширования (AFAIR, в gcc на это годится asm volatile).
Y>>Вообще, судя по http://alenacpp.blogspot.com/2006/04/volatile.html#comment-1976129473176086084 volatile все-таки стоит ставить. N>Угумс.
По сумме треда — нет, смысла нет, кроме специфичных сред.
Здравствуйте, ДимДимыч, Вы писали:
ДД>Здравствуйте, netch80, Вы писали:
N>>Фух... надеюсь, теперь понятно.;)
ДД>Техническая сторона вопроса и раньше была понятна, я не отрицаю существования такой проблемы, но считаю, что метод ее решения — использование volatile — в общем случае неприемлим, и применять его "на всякий случай" неправильно.
Он неприемлем только потому, что отделяет любой доступ к переменной. Если бы он проводил логическую границу только в указанном месте — такой бы проблемы не было. Костыль есть, но он хорошо замаскирован.
Я там дописал уточнение к своему базовому сообщению в треде. В правильно рассчитанных современных средах volatile для межтредового доступа таки не нужен. Для большинства этого достаточно. А если где не так — надеюсь, там документация об этом скажет.
The God is real, unless declared integer.
Re[3]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Спасибо большое, теперь все понятно. Внимательно слежу за вашим с ДимДимычем обсуждением.
Re[5]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
От:
Аноним
Дата:
14.09.09 22:00
Оценка:
Здравствуйте, Zhendos, Вы писали:
Z>Здравствуйте, ДимДимыч, Вы писали:
ДД>>Почему? Можно пример, когда pthread_mutex_lock()/pthread_mutex_unlock() без volatile недостаточно для обеспечения атомарности?
Z>например:
Z>
Z>#include <pthread.h>
Z> static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Z> static int acquires_count = 0;
Z> int
Z> trylock()
Z> {
Z> int res;
Z> res = pthread_mutex_trylock(&mutex);
Z> if (res == 0)
Z> ++acquires_count;
Z> return res;
Z> }
Z>
Хм. Ну да, втыкание volatile "выключает" возможные оптимизации компилятора. И если в оптимизации конкректного компилятора, конкретной версии, с какими-то ключами возможны глюки и их нужно прибивать использованием volatile, то это как-то не тянет на полноценный пример.
Это всего лишь демонстрация бага одного компилятора...
Re[6]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
От:
Аноним
Дата:
15.09.09 05:45
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Zhendos, Вы писали:
А>Это всего лишь демонстрация бага одного компилятора...
если бы вы прочитали обсуждение по ссылкам, то узнали бы, что этот баг
возник из-за того в стандарте C/C++ никак не оговорена многопоточность,
и в соотвествие со стандартом любой компилятор может создать такой код,
что глюки в многопоточной программме потом замучаешься выгребать,
так что если не заморачиваться конкретным компилятором, а писать код в соотвествии со
стандартом, то лучше многопоточность вообще не использовать, до выхода новой редакции стандарта.
Re[7]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, Zhendos, Вы писали:
А>>Это всего лишь демонстрация бага одного компилятора...
А>если бы вы прочитали обсуждение по ссылкам, то узнали бы, что этот баг А>возник из-за того в стандарте C/C++ никак не оговорена многопоточность, А>и в соотвествие со стандартом любой компилятор может создать такой код, А>что глюки в многопоточной программме потом замучаешься выгребать,
А если бы Вы прочитали обсуждение, то увидели бы, что не всё так мрачно, и от того, что этот вопрос решается не "по стандарту" а "по жизни" — проблемы тем не менее уходят и можно работать даже с текущими версиями.
А>так что если не заморачиваться конкретным компилятором, а писать код в соотвествии со А>стандартом, то лучше многопоточность вообще не использовать, до выхода новой редакции стандарта.
Приближающийся стандарт посвящён далеко не только этому, и если бы проблема была только в кэшировании компилятором в многонитевой среде — то он вообще был бы не нужен. В стандарте же основной акцент идёт на проблему синхронизации работы в процессорах в многоядерной/многопроцессорной среде.
И я бы настоятельно попросил не употреблять таких кривых переводов, как "многопоточность". Thread — это нить. Multithreading — многонитевость. В Unix мире принято именно так. Виндовые замашки, где то, что понятие "поток" имеет 4 разных значения, игнорируется — это не для нас.
The God is real, unless declared integer.
Re[7]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
От:
Аноним
Дата:
15.09.09 23:59
Оценка:
Здравствуйте, Аноним, Вы писали:
А>>Это всего лишь демонстрация бага одного компилятора...
А>если бы вы прочитали обсуждение по ссылкам, то узнали бы, что этот баг А>возник из-за того в стандарте C/C++ никак не оговорена многопоточность, А>и в соотвествие со стандартом любой компилятор может создать такой код, А>что глюки в многопоточной программме потом замучаешься выгребать,
Если есть код:
int var;
/* ... */if (cond)
var++;
То я ожидаю, что компилятор сделает так, как я написал, а не так:
int var;
/* ... */
{
register int var_tmp;
var_tmp = var;
if (cond)
var_tmp++;
var = var_tmp;
}
А>так что если не заморачиваться конкретным компилятором, а писать код в соотвествии со А>стандартом, то лучше многопоточность вообще не использовать, до выхода новой редакции стандарта.
Да, я знаю, что компиляторы не идеальны и помимо генерации неверного кода при включенной оптимизации иногда даже валятся где-то у себя внутри. И общепринятый способ — это использовать volatile для затыкания всех возможных багов, вызванных оптимизацией.
Я не разделяю вашей позиции, оправдывающей баги в компиляторах. В примере выше проблема может проявиться не только в многопоточной программе (к примеру, var расположенна во флеше embedded устройства, и служит для подсчёта очень и очень редких аппаратных ошибок, и при написании программы было учтено количество циклов перезаписи флеша, а у нас переменная будет перезаписываться каждый раз, и флеш быстро умрёт), так что спихивать все проблемы на отсутсвие в стандартах четкого описания поведения компилятора в случае многопоточных приложений — по меньшей мере глупо.
Re[8]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
Здравствуйте, Аноним, Вы писали:
А>к примеру, var расположенна во флеше embedded устройства, и служит для подсчёта очень и очень редких аппаратных ошибок, и при написании программы было учтено количество циклов перезаписи флеша, а у нас переменная будет перезаписываться каждый раз, и флеш быстро умрёт
Имхо не очень удачный пример. Как раз если работа с переменной (с областью памяти) вызывает побочные эффекты, которыми нельзя пренебрегать (ресурс eeprom, например, или доростоящий по энергопотреблению цикл записи на внешний носитель), то закладываться на то, что компилятор что-то заоптимизирует — тоже нельзя. В таких случаях нужно четко расписать обращение к "особым" переменным вручную.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
Re[9]: volatile - нужен ли при pthread_mutex_lock() и в GTK?
От:
Аноним
Дата:
16.09.09 09:02
Оценка:
Здравствуйте, ДимДимыч, Вы писали:
ДД>Здравствуйте, Аноним, Вы писали:
А>>к примеру, var расположенна во флеше embedded устройства, и служит для подсчёта очень и очень редких аппаратных ошибок, и при написании программы было учтено количество циклов перезаписи флеша, а у нас переменная будет перезаписываться каждый раз, и флеш быстро умрёт
ДД>Имхо не очень удачный пример. Как раз если работа с переменной (с областью памяти) вызывает побочные эффекты, которыми нельзя пренебрегать (ресурс eeprom, например, или доростоящий по энергопотреблению цикл записи на внешний носитель), то закладываться на то, что компилятор что-то заоптимизирует — тоже нельзя. В таких случаях нужно четко расписать обращение к "особым" переменным вручную.
Хорошо, мы сделаем функцию write_var() с телом, где идёт работа с переменной из eeproma, и разместим её в том же юните трансляции. Теперь включаем оптимизацию, а gcc инлайнит и делает то, что я привёл выше. Будет то же самое
Re[10]: volatile - нужен ли при pthread_mutex_lock() и в GTK
Здравствуйте, Аноним, Вы писали:
А>Хорошо, мы сделаем функцию write_var() с телом, где идёт работа с переменной из eeproma, и разместим её в том же юните трансляции.
Как раз для таких случаев volatile и существует. Объявляем переменную в eeprom'е как volatile, все предварительные вычисления производим с обычными переменными (пусть gcc их оптимизирует, как хочет), а в конце явно инициируем запись результата в volatile-переменную. Мы будем уверены, что при присвоении значения в тексте программы произойдет цикл записи в устройство, и именно тогда, когда нам это будет нужно, не больше и не меньше.
А>Теперь включаем оптимизацию, а gcc инлайнит и делает то, что я привёл выше. Будет то же самое
Если по каким-то причинам функцию нельзя инлайнить, то в gcc для этого есть специальные аттрибуты. Но к рассматриваемому случаю с eeprom это не относится.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)