Как C # гарантирует атомарность операций чтения / записи? - PullRequest
9 голосов
/ 16 января 2010

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

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

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

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

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

Ответы [ 5 ]

15 голосов
/ 16 января 2010

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

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

5 голосов
/ 16 января 2010

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

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

4 голосов
/ 16 января 2010

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

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

3 голосов
/ 16 января 2010

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

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

0 голосов
/ 16 января 2010

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

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