Почему бы не volatile в System.Double и System.Long?
Вопрос вроде моего был спросил, но мой немного отличается. Возникает вопрос: "Почему ключевое слово volatile не разрешено в C#
для типов System.Double
и System.Int64
и т.д.?"
При первом румянце я ответил своему коллеге: "Ну, на 32-битной машине эти типы берут по крайней мере два тика, чтобы даже войти в процессор, а .Net framework имеет намерение абстрагироваться от деталей, специфичных для процессора как это." На что он отвечает: "Это не абстрагирование чего-либо, если оно мешает вам использовать функцию из-за специфики процессора!"
Он подразумевает, что детали, зависящие от процессора, не должны отображаться для человека, использующего фреймворк, который "абстрагирует" детали, подобные этому от программиста. Таким образом, структура (или С#) должна абстрагироваться от них и делать то, что она должна делать, чтобы предлагать те же гарантии для System.Double
и т.д. (Будь то Семафор, барьер памяти или что-то еще). Я утверждал, что структура не должна добавлять накладные расходы на Семафор на volatile
, потому что программист не ожидает таких накладных расходов с таким ключевым словом, потому что Семафор не нужен для 32-битных типов. Большие накладные расходы для 64-разрядных типов могут стать неожиданностью, поэтому лучше, чтобы инфраструктура .Net просто не позволяла это делать, и заставлять вас делать свой собственный Семафор на больших типах, если накладные расходы приемлемы.
Это привело к тому, что мы выяснили, что такое волатильное ключевое слово. (см. эта страница). Эта страница заявляет в примечаниях:
В С# использование изменчивого модификатора в поле гарантирует, что все доступ к этому полю использует VolatileRead или VolatileWrite.
Hmmm..... VolatileRead
и VolatileWrite
обе поддерживают наши 64-битные типы!! Таким образом, мой вопрос:
"Почему ключевое слово volatile не разрешено в C#
для типов System.Double
и System.Int64
и т.д.?"
Ответы
Ответ 1
Не совсем ответ на ваш вопрос, но...
Я уверен, что документация MSDN, на которую вы ссылались, неверна, когда заявляет, что "использование изменчивого модификатора в поле гарантирует, что все доступ к этому полю использует VolatileRead или VolatileWrite".
Непосредственное чтение или запись в поле volatile
генерирует только половину забора (забор при чтении и освобождение при записи).
VolatileRead
и VolatileWrite
методы используйте MemoryBarrier
внутренне, что создает полный забор.
Джо Даффи знает кое-что о параллельном программировании; это то, что он должен сказать об изменчивости:
(В стороне многие думают о разница между нагрузками и хранилища переменных, отмеченные как изменчивые и вызывает Thread.VolatileRead и Thread.VolatileWrite. Разница заключается в том, что прежние API-интерфейсы реализован сильнее, чем код: они достигают приобретения/выпуска семантики, испуская полные заборы на правая сторона. API больше дороже звонить тоже, но, по крайней мере, позволят вам принять решение о позывной на основе callsite-by-callsite, которая индивидуальные нагрузки и магазины нуждаются в MM гарантирует.)
Ответ 2
Он подразумевает, что детали, зависящие от процессора, не должны отображаться для человека, использующего фреймворк, который "абстрагирует" детали, подобные этому от программиста.
Если вы используете методы с низким уровнем блокировки, такие как изменчивые поля, явные барьеры памяти и т.п., то вы полностью находитесь в мире деталей, специфичных для процессора. Вы должны понимать на самом глубоком уровне то, что такое процессор, и не разрешено делать это до переупорядочения, согласованности и т.д., Чтобы написать правильные, портативные, надежные программы, использующие методы с низким уровнем блокировки.
Цель этой функции - сказать: "Я отказываюсь от удобных абстракций, гарантированных однопоточным программированием и обретая возможности повышения производительности благодаря глубокому знанию моего процессора". Вы должны ожидать меньше абстракций в вашем распоряжении, когда вы начинаете использовать методы с низким уровнем блокировки, а не больше абстракций.
Вы идете "вниз к металлу" по какой-то причине, предположительно; цена, которую вы платите, должна иметь дело с причудами упомянутого металла.
Ответ 3
Да. Причина в том, что вы даже не можете читать double
или long
за одну операцию. Я согласен, что это плохая абстракция. У меня такое чувство, что для чтения их атомарно требуется усилие, и это было бы слишком умно для компилятора. Поэтому они позволяют выбрать лучшее решение: lock
ing, Interlocked
и т.д.
Интересно, что на самом деле они могут быть прочитаны атомарно на 32-битной основе с использованием регистров MMX. Это то, что делает java-компилятор JIT. И их можно читать атомарно на 64-битной машине. Поэтому я считаю, что это серьезный недостаток в дизайне.
Ответ 4
Это простое объяснение наследия. Если вы прочитаете эту статью - http://msdn.microsoft.com/en-au/magazine/cc163715.aspx, вы обнаружите, что единственная реализация среды .NET Framework 1.x была на компьютерах x86, поэтому для Microsoft имеет смысл реализовать ее против модели памяти x86. x64 и IA64 были добавлены позже. Таким образом, базовая модель памяти всегда была одной из x86.
Может ли это быть реализовано для x86? Я на самом деле не уверен, что он может быть полностью реализован. Ссылка на двойной, возвращаемый из собственного кода, может быть выровнена с 4 байтами вместо 8. В этом случае все ваши гарантии атомных чтений/записей больше не сохраняются.