С# принципиально не переносимый?

Я уже некоторое время использую C# и недавно начал работать над добавлением параллелизма в свой побочный проект. Итак, согласно Microsoft, читает и записывает в целые числа и даже числа с плавающей запятой. атомарны

Я уверен, что эти требования атомарности прекрасно работают на архитектурах x86. Однако на таких архитектурах, как ARM (которые могут не иметь аппаратной поддержки операций с плавающей запятой), кажется, эти гарантии будут трудными.

Проблема только усугубляется тем фактом, что 'int' всегда 32-битный. Есть много встроенных устройств, которые не могут выполнять 32-битную запись атомарно.

Кажется, это фундаментальная ошибка в C#. Гарантия атомарности этих типов данных не может быть реализована переносимой.

Как эти гарантии атомарности предназначены для реализации на архитектурах, в которых нет FPU или 32-разрядной записи?


person Jake    schedule 29.09.2010    source источник
comment
Это вопрос?   -  person SLaks    schedule 29.09.2010
comment
Многие умные люди участвовали в написании и реализации этой спецификации, я уверен, что они подумали об этом до выдачи гарантии. Возможно, Эрик Липперт сможет объяснить?   -  person Oded    schedule 29.09.2010
comment
@SLaks: Да: как эти гарантии атомарности предназначены для реализации на архитектурах, где нет FPU или 32-битной записи?   -  person Jake    schedule 29.09.2010
comment
@Jake, пожалуйста, отредактируйте вопрос и добавьте к нему сам вопрос, а не комментарий.   -  person Oded    schedule 29.09.2010
comment
@Oded: Я очень на это надеюсь. Одна из причин, по которой мне нравится C#, заключается в том, насколько легко писать переносимый код.   -  person Jake    schedule 29.09.2010
comment
Я считаю, что это то, что называется деталями реализации ... Я не знаю ни одного CLI на основе ARM ... я что-то упустил?   -  person overslacked    schedule 29.09.2010
comment
я не знал об этом - означает ли это, что если я напишу, скажем, класс сущности только с этими типами, он будет потокобезопасным в силу спецификации? в С++ я использовал блокировку логических значений, потому что боялся, что они будут скомпилированы на машине, которая использует 1 инструкцию для изменения памяти...   -  person Aaron Anodide    schedule 29.09.2010
comment
Атомарность типов int/ref — это не функция C#, а часть CLR (которая является реализацией CLI). На этот вопрос можно ответить, если кто-то сможет узнать, как с этим справляются фреймворки Compact и Micro.   -  person Henk Holterman    schedule 29.09.2010
comment
не быть умным, но лично у меня не было проблем с ответом на подразумеваемый вопрос, я прав? к посту :)   -  person Aaron Anodide    schedule 29.09.2010
comment
@Хенк Холтерман. Это раздел 5.5 спецификации С#. Разве это не означает, что это функция независимо от того, где она реализована (компилятор, CLR, аппаратное обеспечение и т. д.).   -  person Conrad Frix    schedule 29.09.2010
comment
@overslacked — Разве Windows Phone 7 не использует C#? Я почти уверен, что телефоны WP7 будут основаны на ARM.   -  person Jake    schedule 29.09.2010
comment
@Jake - Если это так, то я полагаю, что Microsoft написала CLI для процессоров Snapdragon. Реализация CLI специфична для оборудования, на котором она работает. en.wikipedia.org/wiki/Common_Language_Infrastructure   -  person overslacked    schedule 29.09.2010
comment
@overslacked - я не знаю ни о каких интерфейсах командной строки на базе ARM - .NET Compact Framework (включая поддержку процессора ARM) существует со времен framework 1.0, VS.NET (2002 г.) и Pocket PC / Windows Mobile.   -  person Lucas    schedule 30.09.2010
comment
@Lucas - Интересно, у меня не было возможности развиваться против муковисцидоза; это хорошо знать.   -  person overslacked    schedule 30.09.2010


Ответы (5)


Есть две проблемы в отношении «переносимости»:

  1. Can an practical implementation of a language be produced for various platforms
  2. Will a program written in a language be expected to run correctly on various platforms without modification

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

Например, большая часть сетевого кода основана на том факте, что (на большинстве платформ) символ без знака состоит из восьми битов, а 32-битное целое число представлено четырьмя символами без знака в восходящей или нисходящей последовательности. Я использовал платформу, где char был 16 бит, sizeof(int)==1 и sizeof(long)==2. Автор компилятора мог бы заставить компилятор просто использовать нижние 8 бит каждого адреса или мог бы добавить много дополнительного кода, чтобы запись указателя 'char' смещала адрес вправо на один бит (сохраняя младший бит), читая адрес, обновить старшую или младшую половину на основе сохраненного младшего бита адреса и записать его обратно. Любой из этих подходов позволил бы сетевому коду работать без изменений, но сильно затруднил бы полезность компилятора для других целей.

Некоторые гарантии среды CLR означают, что ее нецелесообразно реализовывать на любой платформе с размером атомарной операции менее 32 бит. И что? Если микроконтроллеру требуется больше, чем несколько десятков килобайт пространства для кода и оперативной памяти, разница в стоимости между 8-битным и 32-битным процессором довольно мала. Поскольку никто не собирается запускать какую-либо вариацию CLR на части с 32 КБ пространства кода и 4 КБ ОЗУ, какая разница, сможет ли такой чип удовлетворить свои гарантии.

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

person supercat    schedule 29.09.2010

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

Итог: C# (основной язык, не считая некоторых API для конкретных платформ) так же переносим, ​​как и Java.

person Randolpho    schedule 29.09.2010
comment
Можете ли вы объяснить, что вы имеете в виду: не так уж сложно гарантировать атомарность с помощью проверок во время выполнения? - person Jake; 29.09.2010
comment
Если бы единственным способом записи в 32-битный тип данных была библиотечная подпрограмма, эта подпрограмма могла бы гарантировать, что она никогда не начнет 32-битную запись, пока выполняется другая. Я подозреваю, что именно это произойдет с такими вещами, как Interlocked.Increment для 64-битных значений, поскольку есть явное предупреждение о том, что 64-битные операции Interlocked гарантируют атомарность только в отношении других 64-битных операций Interlocked. - person supercat; 29.09.2010
comment
@Jake: это называется семафор. - person Randolpho; 29.09.2010
comment
Легко — сгенерируйте собственный код, который окружает все обращения к этим типам с соответствующей блокировкой. Вероятно, это будет медленно, но гарантии можно выполнить. - person nobody; 29.09.2010
comment
@ Эндрю - я полагаю, это имеет смысл. Вы можете заблокировать каждое чтение/запись int. Хотя кажется, что это вызовет огромные накладные расходы. Я думаю, это сделало бы его портативным. Но тогда я должен был бы сказать: C# принципиально неэффективен на определенных архитектурах. И его можно было бы сделать более эффективным, удалив это требование, чтобы эти типы вели себя атомарно. - person Jake; 30.09.2010
comment
@Jake: Весь смысл языков более высокого уровня, таких как C#, Java и Python, заключается в том, что мы готовы пожертвовать эффективностью ради быстрой разработки, переносимости (в некоторой степени) и удобства обслуживания (хотя вполне возможно написать необслуживаемый код на любой язык). C# быстрее, чем сырой C? Возможно нет. Сырой C быстрее, чем сборка платформы? Возможно нет. Это имеет значение? Не совсем. - person Randolpho; 30.09.2010
comment
@Randolpho - мне нравится C#. Я хочу, чтобы C# был очень переносимым. Кажется, они могли бы отказаться от атомарного требования «ints / float» и значительно увеличить его. Что плохого в использовании методов Interlocked*, когда нужна атомарность? - person Jake; 30.09.2010
comment
@Jake: а что плохого в том, чтобы не использовать их, когда это гарантируется фреймворком? ИМО, гарантия решает гораздо больше проблем, чем ее отказ. - person Randolpho; 30.09.2010
comment
@Randolpho: Как можно не использовать функцию, которая считывает и записывает в int атомарно? - person Jake; 30.09.2010
comment
@Jake: я хочу сказать, что мы не должны быть вынуждены использовать методы Interlocked *, когда инфраструктура может позаботиться об этом за нас - в этом весь смысл фреймворка, такого как .NET или Java. С тем же успехом вы могли бы утверждать, что нам следует вернуться к неуправляемой памяти. Мы, разработчики, знаем плюсы и минусы управляемой памяти и выбираем плюсы, потому что они перевешивают минусы. - person Randolpho; 30.09.2010

Будущее произошло вчера, C# на самом деле портирован на большое количество встроенных ядер. .NET Micro Framework — типичный сценарий развертывания. Номера моделей, которые я вижу в качестве собственных целей, — это AT91, BF537, CortexM3, LPC22XX, LPC24XX, MC9328, PXA271 и SH2.

Я не знаю точных деталей реализации их основного набора инструкций, но я совершенно уверен, что это все 32-битные ядра, и некоторые из них являются ядрами ARM. Написание многопоточного кода для них требует минимальной гарантии, и атомарные обновления для правильно выровненных слов — одна из них. Учитывая поддерживаемый список и то, что 4-байтовые атомарные обновления для выровненных слов тривиальны для реализации на 32-битном оборудовании, я верю, что все они действительно его поддерживают.

person Hans Passant    schedule 29.09.2010
comment
Я просмотрел каждую из этих архитектур. Мало того, что все они 32-битные, у них также есть выделенные FPU. Это по-прежнему не отвечает на вопрос об архитектурах, которые не являются ни теми, ни другими. - person Jake; 29.09.2010
comment
@Jake: я бы не стал ждать, пока C # будет перенесен на них. В этом мало смысла, выполнение IL требует немного лошадиных сил. - person Hans Passant; 29.09.2010
comment
Лично я все еще жду реализации CLI, которая могла бы работать на моей старой NES. - person Dan Bryant; 30.09.2010
comment
@Dan: ваша старая NES, скорее всего, будет перенесена в CLI :) - person Hans Passant; 30.09.2010
comment
@Dan: лол, кто бы мог подумать, что все эти старые игры для NES будут такими портативными? - person Jake; 30.09.2010
comment
@ Джейк, я не думаю, что авторы эмуляторов NES согласятся. Ранние консольные игры на картриджах, как правило, работали на очень низких уровнях, часто полагаясь на странные особенности поведения ЦП и чипсетов NES. Поскольку это были картриджи, они также могли включать собственную электронику, которая иногда включала специальные сопроцессоры для специальных эффектов, не поддерживаемых основным процессором. В те времена переносимость не вызывала особого беспокойства; разработчики полагались на мельчайшие особенности каждой платформы, пытаясь раздвинуть границы производительности. - person Dan Bryant; 30.09.2010

Вот для чего нужен CLI. Я сомневаюсь, что они сертифицируют реализацию, если она не соответствует требованиям. В общем, C# переносим на любую платформу, на которой он есть.

person Hank Gay    schedule 29.09.2010
comment
Это разочаровывает, так как это требование означает, что интерфейс командной строки не очень переносим. - person Jake; 29.09.2010
comment
@Jake Portable CLI не является разумным ожиданием. JVM и HAL не переносимы. Весь смысл этих технологий в том, что они позволяют другим битам быть переносимыми. - person Conrad Frix; 29.09.2010
comment
@ Джейк: если вы действительно думаете, что C настолько переносим, ​​как вы, кажется, хотели бы, чтобы C # был, вы не знаете о C так много, как вы думаете. - person Randolpho; 30.09.2010
comment
@Randolpho - Какая часть C не переносима? Я хорошо разбираюсь в стандарте и искренне заинтересован. - person Jake; 30.09.2010
comment
Но опять же, C не обещает многого, верно? Это могло измениться с C99, но IIRC C/C++ обещает, например: 1==sizeof(char)‹=sizeof(short)‹=sizeof(int)‹=sizeof(long). Таким образом, компилятор C, в котором sizeof (char) == sizeof (int), будет соответствовать стандарту в соответствии с этим определением. Кроме того, символ IIRC может быть 7 или 9 бит, если sizeof(char) == 1. Бьюсь об заклад, многие программы не могут справиться с 7-битным символом. И снова мои знания могут быть рассинхронизированы, так как я не изучил детали C99. - person Just another metaprogrammer; 30.09.2010
comment
@Jake: @FuleSnabel предоставил отличный пример моей точки зрения. C переносим — до определенного момента. Вы можете написать очень переносимый C - обычно. Но часто всплывают небольшие детали реализации. - person Randolpho; 30.09.2010
comment
@FuleSnabel: C99 гарантирует, что длина символа не менее 8 бит. - person Jake; 30.09.2010
comment
@Randolpho: это не очень хороший момент. Гибкие размеры шрифта — вот почему язык C такой портативный. Мой первоначальный вопрос является примером необоснованно строгого стандарта С#. В результате некоторые архитектуры никогда не смогут поддерживать C#. - person Jake; 30.09.2010
comment
@Jake: Я думаю, у вас может быть другое определение портативности, чем у меня. Если мне приходится прыгать через обручи и иметь дело с пограничными случаями, чтобы написать код, который работает одинаково на двух разных платформах, язык не является переносимым. - person Randolpho; 30.09.2010

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

person Dan Bryant    schedule 29.09.2010