我使用的是Intel Ivy Bridge CPU,并希望在C#中使用RDRAND操作码(https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide)。
如何通过C#调用此CPU指令?我在c#中看到了执行汇编代码的示例:x86/x64 CPUID in C#
但我不确定如何将它用于RDRAND。代码不需要检查执行代码的CPU是否支持该指令。
我执行来自英特尔drng_samples的汇编字节代码的C ++示例:
localhost:8000/mplimage.png
如何将C#中执行汇编代码的示例与来自Intel drng示例代码的C ++代码结合使用?
答案 0 :(得分:4)
SO上有答案会在运行时生成(非托管)汇编代码,以便托管代码回调。这一切都非常有趣,但我建议您只为此目的使用C ++ / CLI,因为它旨在简化互操作方案。创建一个新的Visual C ++ CLR类库,并为其提供一个rdrandwrapper.cpp
:
#include <immintrin.h>
using namespace System;
namespace RdRandWrapper {
#pragma managed(push, off)
bool getRdRand(unsigned int* pv) {
const int max_rdrand_tries = 10;
for (int i = 0; i < max_rdrand_tries; ++i) {
if (_rdrand32_step(pv)) return true;
}
return false;
}
#pragma managed(pop)
public ref class RandomGeneratorError : Exception
{
public:
RandomGeneratorError() : Exception() {}
RandomGeneratorError(String^ message) : Exception(message) {}
};
public ref class RdRandom
{
public:
int Next() {
unsigned int v;
if (!getRdRand(&v)) {
throw gcnew RandomGeneratorError("Failed to get hardware RNG number.");
}
return v & 0x7fffffff;
}
};
}
这是一个非常简单的实现,只是试图模仿Random.Next
获取单个非负随机整数。根据这个问题,它不会尝试验证RDRAND
实际上是否在CPU上可用,但它确实处理了指令存在但无法工作的情况。 (这在当前硬件上“不会发生”,除非它被破坏,详见here。)
生成的程序集是一个混合程序集,可以由托管C#代码使用。确保将程序集编译为x86或x64,与非托管代码相同(默认情况下,项目设置为编译为“任何CPU”,由于非托管代码只有一个特定位,因此无法正常工作)。 p>
using System;
using RdRandWrapper;
class Program {
static void Main(string[] args) {
var r = new RdRandom();
for (int i = 0; i != 10; ++i) {
Console.WriteLine(r.Next());
}
}
}
我对性能没有任何说法,但它可能不是很好。如果你想以这种方式获得许多随机值,你可能希望Next(int[] values)
重载在一次调用中获得许多随机值,以减少互操作的开销。