Вопрос

Может кто-нибудь привести пример подходящего времени для фактического использования "небезопасных" и "исправленных" в коде 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 (ПРОТИВ 80).aspx.

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

поведение в стиле reinterpret_cast

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

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

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

обратите внимание, что именование составлено по образцу Конвертер битов.Удвоение 64 бит

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

// 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);
}

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top