在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
在得到一个非负的随机整数一个非常裸机实现。根据这个问题,它不会试图验证CPU是否实际可用RDRAND
,但它确实可以处理指令存在但无法工作的情况。 (在当前硬件上这是“不可能发生的”,除非它被破坏,详情如下here)。
生成的程序集是一个可以由托管C#代码使用的混合程序集。确保将程序集编译为x86或x64,与非托管代码相同(默认情况下,项目被设置为“Any CPU”,由于非托管代码只有一个特定的位,所以它将无法正常工作)。
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)
重载来在一次调用中获得很多随机值,以减少互操作的开销。
考虑只使用['RNGCryptoServiceProvider'](https://msdn.microsoft.com/library/system.security.cryptography.rngcryptoserviceprovider),这对于大多数需要好于伪随机数的目的来说应该足够好。 –
@JeroenMostert谢谢您的评论。但我真的需要它是真正随机的,以适应科学准确的软件实验的目的。我已经订购了TrueRNGV3,但可能需要很长时间才能到达,同时我正在寻找替代品,而RDRAND似乎很有前途。 –
您不能在C#中执行特定于处理器的程序集。您可以为它编写一段C++代码,并使用C++/CLI或P/Invoke进行封装,如[在此]中所述(https://stackoverflow.com/questions/13436130/)。 –