Как C# гарантирует атомарность операций чтения-записи?

Состояния спецификации C# в разделе 5.5, который читает и пишет на определенных типах (а именно, bool, char, byte, sbyte, short, ushort, uint, int, float, и ссылочные типы), как, гарантируют, будут атомарными.

Это возбудило мой интерес. Как можно сделать это? Я имею в виду, мой непритязательный личный опыт только показал мне, чтобы заблокировать переменные или использовать барьеры, если я хотел, чтобы чтения и записи выглядели атомарными; это было бы уничтожителем производительности, если бы он должен был быть сделан для каждого чтения-записи. И все же C# делает что-то с подобным эффектом.

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

Я понимаю, что этому, возможно, придется иметь дело с определенными определенными инструкциями по процессору и не может быть применимо в C/C++. Однако я все еще хотел бы знать, как это работает.

[РЕДАКТИРОВАНИЕ], По правде говоря я полагал, что чтения и записи могли быть неатомарными в определенных условиях, как ЦП мог получить доступ к ячейке памяти, в то время как другой ЦП пишет там. Это только происходит, когда ЦП не может рассматривать весь объект сразу, как то, потому что это является слишком большим или потому что память не выровненная на надлежащей границе?

9
задан zneak 26 February 2014 в 16:22
поделиться

5 ответов

Причина, по которой эти типы имеют гарантированную атомарность, заключается в том, что все они имеют 32 бита или меньше. Поскольку .NET работает только на 32-х и 64-х битных операционных системах, процессорная архитектура может читать и записывать все значение за одну операцию. Это в отличие от, скажем, Int64 на 32-битной платформе, которая должна быть прочитана и записана с использованием двух 32-битных операций.

Я на самом деле не разбираюсь в аппаратном обеспечении, поэтому я извиняюсь, если моя терминология заставляет меня звучать как шут, но это основная идея.

15
ответ дан 4 December 2019 в 09:13
поделиться

Необходимо использовать псевдоним, если вы используете одно и то же имя дважды:

SELECT FROM grades g1 ... 
JOIN grades g2 ON g1.id = g2.grade_id ...

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

-121--1658025-

Редко ответ в этом потоке отвечает на вопрос. Вместо того, чтобы взять простой выход, я возьму удар:

Несколько преимуществ, которые не были упомянуты (JScript-centric):

  • Вы можете выучить весь язык и сохранить его в памяти, если вы используете его достаточно - я не знаю никого, кто утверждает, что знает весь .NET framework; это делает кодирование очень быстрым.
  • Слабая типизация - это может позволить вам быстрее кодировать что-либо, например, вы действительно заботитесь о разнице между char и последовательностей большую часть времени? (вставить религиозное пламя-война здесь)
  • Eval : это очень злонамеренное ключевое слово на самом деле невероятно мощное, и позволяет манипулировать вашим кодом во время выполнения действительно интересными способами
  • Совместимость языка клиента/сервера : сходство JScript с Javascript означает, что вы можете использовать тот же файл включения для проверки на стороне сервера, что и для клиентской стороны.
-121--1033717-

Довольно дешево реализовать гарантию атомности на ядрах x86 и x64, так как CLR обещает атомарность только для переменных, которые являются 32-разрядными или меньшими. Все, что требуется, это то, что переменная правильно выровнена и не охватывает строку кэша. Компилятор JIT обеспечивает это, распределяя локальные переменные по 4-байтовому смещению стека. Менеджер кучи GC делает то же самое для выделения кучи.

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

5
ответ дан 4 December 2019 в 09:13
поделиться

Вы никогда не хотите использовать sbrk вместо malloc или free . Он не является портативным и обычно используется только исполнителями стандартной библиотеки Си или в тех случаях, когда он недоступен. Он довольно хорошо описан на странице :

Описание

brk () устанавливает конец сегмента данных до значения, указанного end_data_segment, когда это значение разумно, система действительно имеет недостаточно памяти, а процесс не превысить максимальный размер данных (см. setrlimit (2)).

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

Возвращаемое значение

При успешном возврате brk () ноль, и sbrk () возвращает указатель на начало новой области. При ошибке, Возвращается значение -1, а значение errno равно ENOMEM.

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


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

-121--3894526-

На мой взгляд, ЗАВИТОК прост и прост в выборе. В PHP Cookbook (O'Reilly, 2002) ЗАВИТОК был выбран по различным (исполнительским) причинам.

-121--3181293-

На x86 чтения и записи в любом случае атомарны. Поддерживается на аппаратном уровне. Однако это не означает, что операции, такие как сложение и умножение, являются атомарными; они требуют нагрузки, вычисления, затем хранения, что означает, что они могут вмешиваться. Здесь и появляется префикс блокировки.

Вы упомянули барьеры блокировки и памяти; они не имеют никакого отношения к тому, что чтение и запись являются атомарными. Нет пути для x86 с или без использования барьеров памяти, что вы собираетесь увидеть наполовину записанное 32-битное значение.

4
ответ дан 4 December 2019 в 09:13
поделиться

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

-4
ответ дан 4 December 2019 в 09:13
поделиться

Да, C # и Java гарантируют, что нагрузки и магазины некоторых примитивных типов являются атомными, как вы говорите. Это дешево, потому что процессоры, способные работать .NET или JVM, гарантируют, что нагрузки и магазины соответствующим образом выровненные примитивные типы являются атомными.

Теперь, что ни C # ни Java, ни процессоры, которые они не работают на гарантии, и что дорого, это выпускает барьеры памяти, чтобы эти переменные можно было использовать для синхронизации в многопоточной программе. Однако в Java и C # вы можете пометить вашу переменную с помощью «волатильного» атрибута, и в этом случае компилятор заботится о выдаче соответствующих барьеров памяти.

3
ответ дан 4 December 2019 в 09:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: