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

Является двунаправленным атомом на архитектуре Intel?

У моего коллеги и я есть аргумент в пользу атомарности чтения двойника по архитектуре Intel с использованием С#.NET 4.0. Он утверждает, что мы должны использовать метод Interlocked.Exchange для записи в double, но просто чтение двойного значения (в каком-то другом потоке) гарантировано будет атомарным. Мой аргумент заключается в том, что .NET не гарантирует эту атомарность, но его аргумент заключается в том, что на архитектуре Intel это гарантировано (возможно, не на AMD, SPARC и т.д.).

Любые эксперты Intel и .NET обмениваются некоторыми источниками света на этом?

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

4b9b3361

Ответ 1

Да и нет. На 32-разрядных процессорах он не гарантируется атомарным, потому что double больше, чем родной слова. На 64-битном процессоре правильно выровненный доступ является атомарным. 64-разрядный CLI гарантирует все до 64-битного чтения как атомарное. Таким образом, вам нужно будет создать сборку для x64 (не любой CPU). В противном случае, если ваша сборка может быть запущена на 32-битной основе, лучше использовать Блокировка, см. Атоматичность, волатильность и неизменность разные, часть два Эрика Липперта. Я думаю, вы можете положиться на знания Эрика Липперта о Microsoft CLR.

Стандарт CLI ECMA также поддерживает это, хотя сам С# не гарантирует его:

Соответствующий CLI должен гарантировать, что доступ для чтения и записи правильно выровненные ячейки памяти не превышают размер родного слова (размер типа int int) является атомарным (см. §I.12.6.2)

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

Другой связанный вопрос Какие операции являются атомарными в С#?.

Ответ 2

У моего коллеги и я есть аргумент в пользу атомарности чтения двойника по архитектуре Intel с использованием С#.NET 4.0.

Intel гарантирует, что 8 байтовых двойников являются атомарными при чтении и записи при согласовании с 8-байтовой границей.

С# не гарантирует, что double выровнен по границе 8 байтов.

Он утверждает, что мы должны использовать метод Interlocked.Exchange для записи в double, но просто чтение двойного значения (в каком-то другом потоке) гарантировано будет атомарным.

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

Мой аргумент заключается в том, что .NET не гарантирует эту атомарность, но его аргумент заключается в том, что на архитектуре Intel это гарантировано (возможно, не на AMD, SPARC и т.д.).

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

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

Не сочетайте атомарность с волатильностью.

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

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

Ответ 3

Чтение или запись двойника является атомарным по архитектуре Intel, если они выровнены по 8-байтовой границе адреса. См. Является обновлением атома двойного действия.

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

Считывание и запись следующих типов данных: atomic: bool, char, байтов, sbyte, short, ushort, uint, int, float и reference. В добавление, чтение и запись типов перечислений с базовым типом в предыдущий список также является атомарным. Читает и пишет другие типы, включая длинные, улунговые, двойные и десятичные, а также определяемые пользователем типы, не гарантируются как атомарные.

Используйте Interlocked для чтения и записи, чтобы быть в безопасности. Это гарантирует атомарность. В архитектуре, где она по умолчанию является атомарной, она не должна создавать накладных расходов. Вы должны использовать Interlocked для чтения, а также для записи, чтобы убедиться, что не прочитаны частично записанные значения (цитата из InterLocked.Read() документации):

Метод Read и 64-разрядные перегрузки Increment, Decrement, и методы Add действительно являются атомами только в системах, где System.IntPtr имеет длину 64 бит. В других системах эти методы являются атомарными с уважения друг к другу, но не в отношении других средств доступ к данным. Таким образом, для обеспечения безопасности потоков на 32-битных системах любой доступ к 64-битовому значению должен осуществляться через членов Класс блокировки.