C # небезопасный / фиксированный код - PullRequest
30 голосов
/ 17 сентября 2008

Может ли кто-нибудь привести пример хорошего времени для фактического использования "небезопасных" и "исправленных" в коде C #? Я играл с ним раньше, но на самом деле никогда не нашел для него пользы.

Рассмотрим этот код ...

fixed (byte* pSrc = src, pDst = dst) {
    //Code that copies the bytes in a loop
}

по сравнению с простым использованием ...

Array.Copy(source, target, source.Length);

Второй - это код, найденный в .NET Framework, первая часть кода, скопированная с веб-сайта Microsoft, http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx.

Встроенный Array.Copy () значительно быстрее, чем использование небезопасного кода. Это может быть просто потому, что второе написано лучше, а первое - просто пример, но в каких ситуациях вам действительно понадобится использовать небезопасный / фиксированный код для чего-либо? Или этот бедный веб-разработчик балуется чем-то над головой?

Ответы [ 7 ]

29 голосов
/ 17 сентября 2008

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

Если вы используете P / Invoke, маршаллер по умолчанию будет прикреплять объекты за вас. Иногда необходимо выполнить пользовательский маршаллинг, а иногда необходимо закрепить объект дольше, чем продолжительность одного вызова P / Invoke.

21 голосов
/ 17 сентября 2008

Я использовал небезопасные блоки для манипулирования растровыми данными. Доступ к необработанным указателям значительно быстрее, чем SetPixel / GetPixel.

unsafe
{
    BitmapData bmData = bm.LockBits(...)
    byte *bits = (byte*)pixels.ToPointer();
    // Do stuff with bits
}

«исправлено» и «небезопасно» обычно используется при взаимодействии или когда требуется дополнительная производительность. То есть. String.CopyTo () использует небезопасные и исправленные в своей реализации.

8 голосов
/ 28 января 2009

Поведение стиля reinterpret_cast

Если вы немного манипулируете, то это может быть невероятно полезным

Многие высокопроизводительные реализации хеш-кода используют UInt32 для значения хеш-кода (это упрощает сдвиги). Поскольку .Net требует Int32 для метода, вы хотите быстро преобразовать uint в int. Поскольку не имеет значения, каково действительное значение, только для того, чтобы все биты в значении были сохранены, требуется переинтерпретация.

public static unsafe int UInt32ToInt32Bits(uint x)
{
    return *((int*)(void*)&x);
}

обратите внимание, что именование смоделировано на BitConverter.DoubleToInt64Bits

Продолжая в духе хеширования, преобразование основанной на стеке структуры в байт * позволяет легко использовать функции байтового хеширования:

// from the Jenkins one at a time hash function
private static unsafe void Hash(byte* data, int len, ref uint hash)
{
    for (int i = 0; i < len; i++)
    {
        hash += data[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
}

public unsafe static void HashCombine(ref uint sofar, long data)
{
    byte* dataBytes = (byte*)(void*)&data;
    AddToHash(dataBytes, sizeof(long), ref sofar);
}

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

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

fixed необходим, когда вы хотите взаимодействовать с какой-нибудь полезной неуправляемой функцией (их много), которая принимает массивы или строки в стиле c. Таким образом, в сценариях взаимодействия это касается не только соображений производительности, но и корректности.

4 голосов
/ 17 сентября 2008

Небезопасно полезно (например) для быстрого получения пиксельных данных из изображения с помощью LockBits. Повышение производительности по сравнению с использованием управляемого API составляет несколько порядков.

2 голосов
/ 17 сентября 2008

Нам пришлось использовать фиксированное значение, когда адрес передается в устаревшую C-библиотеку. Поскольку DLL поддерживала внутренний указатель на вызовы функций, весь ад мог бы развалиться, если бы GC сжал кучу и переместил все вокруг.

1 голос
/ 17 сентября 2008

Это говорит о том, что разработчики .NET Framework хорошо поработали, чтобы охватить проблемное пространство - убедиться, что среда «управляемого кода» может делать все, что традиционный подход (например, C ++), может делать с небезопасным кодом указатели. В случае, если это невозможно, небезопасные / фиксированные функции есть, если они вам нужны. Я уверен, что у кого-то есть пример, где нужен небезопасный код, но на практике он кажется редким - а в этом суть, не так ли? :)

1 голос
/ 17 сентября 2008

Я считаю, что небезопасный код используется, если вы хотите получить доступ к чему-то вне среды выполнения .NET, т.е. это не управляемый код (без сборки мусора и т. д.). Это включает в себя необработанные вызовы Windows API и все такое прочее.

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