КАК локальные статические переменные небезопасны в c? - PullRequest
0 голосов
/ 11 июня 2018

Так что, просматривая Интернет, я не мог найти последовательную и полезную информацию об этом.Итак, вот в чем проблема:

Почему локальные статические переменные в C считаются поточно-небезопасными?Я имею в виду, что статические локальные переменные хранятся в сегменте данных, который используется всеми потоками, но разве внутренняя связь не должна мешать потокам входить в статические переменные друг друга?

Этот пост на форуме , кажется, предполагает, что потоки фактически время от времени вступают в сегмент данных друг друга, но разве такое поведение явно не нарушает все стандарты c, начиная с 90-х годов?Если бы такое поведение ожидалось, разве использование сегмента данных (т. Е. Всех переменных со статической продолжительностью хранения, включая глобальные переменные) давно не было бы признано устаревшим в последовательных стандартах c?

Я действительно не понимаюЯ не понимаю этого, поскольку у каждого, похоже, есть что-то против локальных статических переменных, но люди не могут прийти к единому мнению, почему, а исследование некоторых аргументов показывает, что они были непродуманны.

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

Насколько я вижу, существуют вполне законные применения локальных статических переменных.Но может я что-то упустил?Я действительно хотел бы знать, если бы это было так.

[РЕДАКТИРОВАТЬ]: Ответы здесь были довольно полезными.Спасибо всем за понимание.

Ответы [ 5 ]

0 голосов
/ 11 июня 2018

разве внутренняя связь не должна помешать потокам войти в статические переменные друг друга?

Ваш вопрос помечен .В языке программирования Си нет потоков.Если ваша программа создает какие-либо новые потоки, она делает это, вызывая некоторую библиотеку во время выполнения.Цепочка инструментов C не знает, что такое потоки, у нее нет никакого способа узнать, что вызываемые вами библиотечные процедуры создают потоки, и у нее нет никакого способа узнать, считаете ли вы какую-либо конкретную статическую переменную «принадлежащей» одному или другому потоку.thread.

Каждый поток в вашей программе работает в том же виртуальном адресном пространстве, что и любой другой поток.Каждый поток потенциально имеет доступ ко всем тем же переменным, к которым может обращаться любой другой поток.Если переменная в программе на самом деле используется более чем одним потоком, то ответственность программиста *1013* (не ответственность цепочки инструментов) лежит на том, чтобы потоки использовали ее безопасным образом..

Кажется, что каждый имеет что-то против локальных статических переменных,

Разработчики программного обеспечения, которые работают в командах для разработки больших, долговечных программных систем (подумайте, десятки лети от сотен тысяч до десятков миллионов строк кода) есть несколько очень хорошо понятных причин избегать использования статических переменных.Не каждый работает в подобных системах, но здесь вы встретите людей, которые делают.

люди, похоже, не могут согласиться с тем, почему

Не все программные системы необходимо обслуживать и обновлять в течение десятков лет, и не все имеют десятки миллионов строк кода.Это большой мир.Есть люди, которые пишут код по разным причинам.У них не все одинаковые потребности.

, и исследование некоторых аргументов показывает, что они непродуманны

Есть люди, которые пишут код для самых разныхпричины ... То, что кажется «непродуманной», чтобы вы могли бы быть то, что какой-либо другой группой разработчиков думали долго и упорно о.Возможно, вы не до конца понимаете их потребности.

Насколько я понимаю, существуют вполне законные варианты использования локальных статических переменных

Да.Вот почему они существуют.Язык программирования C, как и многие другие языки программирования, является общим инструментом, который можно использовать по-разному.

0 голосов
/ 11 июня 2018

С моей точки зрения, база неверна или, по крайней мере, она так же небезопасна, как и любой другой плохой дизайн.

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

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

Если вы говорите о статической локальной переменной, которую можно записать / прочитать / .. из двухразличные задачи без защиты (через обратный вызов или что-то еще), это ужасный дизайн (иусиление, ошибка разработчиков), но нет, потому что статические локальные переменные (как правило) небезопасны.

0 голосов
/ 11 июня 2018

разве внутренняя связь не должна мешать потокам входить в статические переменные друг друга?

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

Я, например, считаю, что локальные статические переменные являются очень хорошим способом передачи информации между вызовами функций, которые действительно могут улучшить читаемость и ограничить область действия

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

Основная причина проблемы заключается в том, что использование переменных со статическим связыванием для чтения / записи преобразует форму функции без сохранения состояния с сохранением состояния.Без статических переменных любое состояние, контролируемое функцией, должно быть передано ей извне;статические переменные, с другой стороны, позволяют функциям сохранять «скрытое» состояние.

Чтобы увидеть последствия сохранения скрытого состояния, рассмотрим функцию strtok: вы не можете использовать ее одновременно, поскольку несколько потоков могут наступитьсостояние друг друга.Более того, вы не можете использовать его даже из одного потока, если хотите проанализировать каждый токен из строки, которая в данный момент анализируется, потому что ваш вызов второго уровня будет мешать вашему собственному вызову верхнего уровня.

0 голосов
/ 11 июня 2018

но разве внутренняя связь не должна мешать потокам вмешиваться в статические переменные друг друга?

Нет, связь не имеет ничего общего с безопасностью потоков.Он просто ограничивает функции от доступа к переменным, объявленным в других областях, что является другим и не связанным с этим вопросом.

Предположим, у вас есть такая функция:

int do_stuff (void)
{
  static int x=0;
  ...
  return x++;
}

и затем эта функция вызываетсянесколькими потоками, потоком 1 и потоком 2. Функции обратного вызова потока не могут получить прямой доступ к x, поскольку он имеет локальную область видимости.Однако они могут позвонить do_stuff() и одновременно.И тогда вы получите следующие сценарии:

  • Поток 1 выполнил do_stuff до тех пор, пока точка не вернет 0 вызывающей стороне.
  • Поток 1 собирается записать значение 1 до x, но до этого ..:
  • Переключение контекста, поток 2 входит и выполняет do_stuff.
  • Поток 2 читает x, он все еще 0, поэтому он возвращает 0 вызывающей стороне, а затем увеличивает x на 1.
  • x теперь 1.
  • Тема 1 снова получает фокус.Он собирался сохранить от 1 до x, вот что он делает.
  • Теперь x по-прежнему 1, хотя, если программа вела себя правильно, она должна была быть 2.

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

Этоявляется «условием гонки», и решение здесь состоит в том, чтобы защитить x мьютексом или аналогичным механизмом защиты.Это сделает функцию поточно-безопасной .В качестве альтернативы, do_stuff может быть переписано, чтобы не использовать статические переменные хранения или подобные ресурсы - тогда это будет повторный вход .

0 голосов
/ 11 июня 2018

Поведение одновременного чтения и записи любого неатомарного объекта равно undefined в C.

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

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

Aсвоего рода на полпути; локальное хранилище потоков доступно с некоторыми компиляторами C, но оно еще не включено в стандарт C (см. thread_local из C ++ 11).См. Например, https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Thread-Local.html

...