【问题标题】:C# Unsafe/Fixed CodeC# 不安全/固定代码
【发布时间】:2010-09-10 06:32:31
【问题描述】:

有人可以举例说明在 C# 代码中实际使用“不安全”和“固定”的好时机吗?我以前玩过它,但从未真正找到它的好用处。

考虑这段代码...

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

相比于简单地使用...

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

第二个是在.NET Framework中找到的代码,第一部分是从微软网站http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx复制的代码。

内置的 Array.Copy() 比使用不安全代码快得多。这可能只是因为第二个写得更好,第一个只是一个例子,但是你真的需要在什么情况下使用不安全/固定代码?还是这个可怜的 Web 开发人员在搞乱他头上的事情?

【问题讨论】:

    标签: c# .net unsafe fixed


    【解决方案1】:

    它对于与非托管代码的互操作很有用。任何传递给非托管函数的指针都需要修复(也称为固定),以防止垃圾收集器重新定位底层内存。

    如果您使用的是 P/Invoke,则默认编组器将为您固定对象。有时需要执行自定义编组,有时需要固定对象的时间超过单个 P/Invoke 调用的持续时间。

    【讨论】:

      【解决方案2】:

      我使用了不安全的块来操作位图数据。原始指针访问比 SetPixel/GetPixel 快得多。

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

      “固定”和“不安全”通常在进行互操作或需要额外性能时使用。 IE。 String.CopyTo() 在其实现中使用不安全和固定的。

      【讨论】:

      • 我会将“显着”更改为“许多数量级”。令人难以置信的是 SetPixel 和 GetPixel 的速度有多慢。 1980 年,Apple IIe 上的像素访问速度更快。
      【解决方案3】:

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

      unsafe 也(从 2.0 开始)允许您使用 stackalloc。这在需要一些小的可变长度数组(如临时空间)的高性能情况下非常有用。

      所有这些用途都坚定地属于“仅当您的应用程序确实需要性能时”,因此在一般用途中是不合适的,但有时您确实需要它。

      fixed 当你希望与一些有用的非托管函数(有很多)进行互操作时是必需的,这些函数采用 c 样式的数组或字符串。因此,这不仅是出于性能原因,也是出于互操作场景中的正确性原因。

      【讨论】:

      • 你为什么提到 reinterpret_cast ? unsafe/fixed 的并行是什么?
      • @Guillame07 因为直接执行一个(而不是在结构上使用联合)需要一个不安全的上下文
      【解决方案4】:

      Unsafe 可用于(例如)使用 LockBits 快速从图像中获取像素数据。与使用托管 API 相比,性能提升了几个数量级。

      【讨论】:

        【解决方案5】:

        当地址被传递给旧版 C DLL 时,我们必须使用固定值。由于 DLL 在函数调用之间维护了一个内部指针,如果 GC 压缩堆并移动东西,所有地狱都会崩溃。

        【讨论】:

          【解决方案6】:

          如果您想访问 .NET 运行时之外的内容,我相信会使用不安全代码,即。它不是托管代码(没有垃圾收集等)。这包括对 Windows API 和所有爵士乐的原始调用。

          【讨论】:

          • “不安全”并不意味着“不受管理”。 C# 中的不安全方法是允许操作指针的托管方法。但是,代码仍然是受管理的。如果您想在应用程序中使用非托管(本机)代码,可以使用 C++/CLI 及其#pragma 指令。
          • 冒险的想法,垃圾收集器在不安全的方法/变量/对象上不活动,如果您处理现有变量并固定此类数据结构,则可以,但是如果您扩展数据,它确实会出现问题不安全的区域,如果做错了,它会吃掉内存,而不受 GBC 的控制。虽然可以有数据并使用不安全的方法对其进行处理,但如果该过程不泄漏,则没有风险,处理后 GBC 可以接管。
          【解决方案7】:

          这告诉我 .NET 框架的设计者在解决问题空间方面做得很好——确保“托管代码”环境可以完成传统(例如 C++)方法可以处理其不安全代码的所有事情/指针。万一它不能,如果你需要它们,不安全/固定的功能就在那里。我敢肯定有人有一个需要不安全代码的例子,但在实践中似乎很少见——这才是重点,不是吗? :)

          【讨论】:

          • 用于图形操作,比 marshal.copy 更快,用于实时数据处理 ea 音频。但是您可能不会在普通的 MVC 站点中看到它,通常与 c/c++ /assembler 结合使用。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-03-11
          • 1970-01-01
          • 1970-01-01
          • 2011-08-06
          • 1970-01-01
          • 1970-01-01
          • 2011-04-30
          相关资源
          最近更新 更多