2015-06-24 1 views
0

Я смущен этот вопрос:
У меня есть функция C++:Как взаимодействие контекста потока работает с глобальной переменной?

void withdraw(int x) { 
    balance = balance - x; 
} 

balance является глобальной целочисленной переменной, которая равна 100 на старте.
Мы запускаем вышеуказанную функцию с двумя различными резьбами: резьбой A и резьбой B. Резьба A Запуск withdraw(50) и резьба B run withdraw(30).

Предполагая, что мы не защищаем balance, каков конечный результат balance после запуска этих потоков в следующих последовательностях?

  1. A1-> A2-> A3-> В1-> В2> В3
  2. В1-> В2> B3-> A1-> A2-> A3
  3. A1-> A2-> В1-> В2> B3-> A3
  4. В1-> В2> A1-> A2-> A3-> B3

Объяснение:

  • A1 означает OS выполнить первый линия функции withdraw в потоке A, A2 означает, что ОС выполняет вторую строку функции withdraw в потоке A, B3 означает, что ОС выполняет третью строку функции withdraw в потоке B и т. Д.

  • Последовательность заключается в том, как график расписания ОС A & B предположительно.

Мой ответ

  1. 50 (Перед тем как переключение контекста, OS сохраняет balance. После переключения контекста, OS восстановление balance до 50)
  2. 70 (Похожие выше)

Но мой fr iend не согласен, он сказал, что balance является глобальной переменной. Таким образом, он не сохраняется в стеке, поэтому он не влияет на переключение контекста. Он утверждал, что все 4 последовательности приводят к 20.

Итак, кто прав? Я не могу придраться к его логике.

(Предположим, у нас есть один процессор, который может выполнять только один поток в то время)

+0

Что вы подразумеваете под строкой 1,2,3? Функция имеет только одну строку – MikeMB

+0

Из того, что я понимаю, строка 1 - '{', строка 2 - это 'balance = balance - x' line 3 is'} '. –

+0

Тогда я не вижу смысла вопроса, потому что декремент произойдет «атомарно» (если вы разрешаете прерывание между линиями). Типичным способом разделить это будет 1: Нагрузка, если баланс из памяти 2: уменьшить значение на X, 3: вернуть результат обратно на баланс. – MikeMB

ответ

0

UNLESS стандарта заправочной вы используете указывает, то нет никакого способа узнать. Большинство типичных стандартов на резьбу нет, поэтому обычно не существует способа узнать.

Ваш ответ звучит как вздор. ОС не знает, что такое balance и какой-либо способ сделать что-либо для контекстного коммутатора. Кроме того, потоки могут работать одновременно без контекстных переключателей.

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

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

+0

Если у нас есть один процессор, который может выполнять только один поток за раз, не нужен ли контекстный переключатель? –

+0

@acx_cosmos Да. –

+0

Так что, даже если мы можем выполнить только один поток за раз, результат все равно будет непредсказуемым? –

0

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

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

И поскольку переключение контекста не имеет значения, ОС не сохранит и не восстановит что-либо. Он не будет касаться баланса переменных. Только ваши два потока будут.

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

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

+0

Если у нас есть один процессор, который может выполнять только один поток за раз, не нужен ли контекстный переключатель? –

0

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

balance = balance - x; 

Поток А читает баланс. Это 100. Теперь нить A вычитает 50 и ... oops

Резьба B считывает баланс. Это 100. Теперь поток B вычитает 30 и обновляет переменную, которая теперь равна 70.

... thread A продолжает и обновляет переменную, которой теперь 50. Вы только что полностью потеряли работу Thread B.

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

0

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

balance = balance - x; 

Поток А читает баланс. Это 100. Теперь нить A вычитает 50 и ... oops

Резьба B считывает баланс. Это 100. Теперь поток B вычитает 30 и обновляет переменную, которая теперь равна 70.

... thread A продолжает теперь обновляет переменную, которой теперь 50. Вы только что потеряли работу, которую Thread B ,

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

0

Простой и короткий ответ для C++: Несинхронизированный доступ к общей переменной - это неопределенное поведение, поэтому все может случиться. Значение может, например, 100,70,50,20,42 или -458995. Программа может потерпеть крах или нет. И в теории его даже позволили заказать пиццу.

Фактический машинный код, который выполняется, обычно находится далеко от того, что выглядит в вашей программе, и в случае неопределенного поведения вам больше не гарантировано, что фактическое поведение имеет какое-либо отношение к написанному вами коду C++ ,

+0

Вы подразумеваете, что контекстное переключение вообще не имеет значения, поскольку 4 последовательности могут привести к чему-либо, правильно? –

+0

Исправить. Тип анализа, который вы выполняете, имеет смысл только в том случае, если баланс будет иметь тип 'std :: atomic '. – MikeMB

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