Подтвердить что ты не робот

С# принудительный порядок выполнения инструкции

Мой вопрос о порядке выполнения гарантий в С# (и предположительно .Net вообще). Я даю примеры Java, с которыми я знаю что-то, что можно сравнить.

Для Java (от "Java Concurrency на практике" )

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

Итак, код

  y = 10;
  x = 5;
  a = b + 10;

может фактически назначить a = b + 10 Перед назначением y = 10

И на Java (из той же книги)

Все нитки A, выполняемые в или перед синхронизированным блоком, видны в потоке B, когда он запускает синхронизированный блок, защищенный одной и той же блокировкой.

поэтому в Java

 y = 10;
 synchronized(lockObject) {
     x = 5;
 }
 a = b + 10;

y = 10 и x = 5 гарантированы, что оба выполняются до a = b + 10 (я не знаю, будет ли y = 10 гарантировано работать до x = 5).

Какие гарантии делает код С# для порядка выполнения для операторов С#

 y = 10;
 lock(lockObject) {
     x = 5;
 }
 a = b + 10;

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

4b9b3361

Ответ 1

ISO 23270: 2006 — Информационные технологии и языки программирования: С#, & sect; 10.10 говорит (и цитирую):

10.10 Порядок выполненияВыполнение должно выполняться таким образом, чтобы побочные эффекты каждого исполняемого потока сохраняются в критических точках выполнения. Определен побочный эффект как чтение или запись изменчивого поля, запись в энергонезависимую переменную, запись на внешний ресурс и выброс исключения. Критические точки выполнения, при которых порядок этих побочных эффектов должны сохраняться ссылки на изменчивые поля (§17.4.3), lock (§15.12), а также создание и завершение потоков. Реализация может свободно изменять порядок выполнения программы С#, с учетом следующих ограничений:

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

  • Правила упорядочения инициализации сохраняются (§17.4.4, §17.4.5).

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

Другие стандарты CLI также доступны бесплатно от ISO на

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

Ответ 2

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

y = 10;
Thread.MemoryBarrier();
x = 5;
Thread.MemoryBarrier();
a = b + 10;
Thread.MemoryBarrier();
// ...

От msdn

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

Ответ 4

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