C # соблюдение порядка выполнения операторов - PullRequest
13 голосов
/ 13 мая 2011

Мой вопрос касается порядка гарантий выполнения в C # (и, предположительно, .Net в целом). Я привожу примеры на Java, с которыми я могу что-то сравнить.

Для Java (из "Параллелизма Java на практике")

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

Итак, код

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

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

А на Яве (из той же книги)

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

так в Java

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

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

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

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

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

Ответы [ 4 ]

6 голосов
/ 13 мая 2011

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

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

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

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

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

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

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

5 голосов
/ 13 мая 2011

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

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

From msdn

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

3 голосов
/ 13 мая 2011

То, что вы ищете, это Thread.MemoryBarrier

Однако они могут не быть необходимыми для текущей реализации Microsoft .NET. Подробнее см. Этот вопрос .

1 голос
/ 13 мая 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...