我有一个ASP.NET应用程序依赖于Random类来生成伪随机字符串。它使用以下代码(这是Google为应用程序SSO提供的更大范围的示例代码的一部分):
public static class SamlUtility
{
private static Random random = new Random();
private static char[] charMapping = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' };
public static string CreateId()
{
byte[] bytes = new byte[20]; // 160 bits
random.NextBytes(bytes);
char[] chars = new char[40];
for (int i = 0; i < bytes.Length; i++)
{
int left = (bytes[i] >> 4) & 0x0f;
int right = bytes[i] & 0x0f;
chars[i * 2] = charMapping[left];
chars[i * 2 + 1] = charMapping[right];
}
return new string(chars);
}
}
这通常效果很好,但有时会开始生成一串'a'。从我从调试中可以看出,Random只是停止返回随机数,而是反复填充具有相同值的字节。我通过使用GUID来修补此问题,但我很好奇原始代码中发生了什么。我假设某种形式的熵耗尽,但我在文档中找不到任何参考。此外,每次发生这种情况时,执行iisreset都会恢复正确的行为。
对于出现问题的任何建议都会非常感激。
答案 0 :(得分:6)
Random
类不是线程安全的
如果您同时在多个线程上的同一实例上生成随机数,则其内部状态将被破坏,并且它将开始返回零。
您需要创建Random
实例[ThreadStatic]
以确保每个实例不被多个线程共享。
请注意,[ThreadStatic]
字段的初始值设定项只会运行一次,因此每次使用该字段时都需要检查它是否null
并在必要时进行初始化。
在种子中包含线程ID和当前时间以防止种子冲突也是一个好主意。
请注意,Random
类不安全;考虑使用RNGCryptoServiceProvider
class