随机数发生器返回零

时间:2010-09-20 18:09:55

标签: c# .net asp.net random

我有一个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都会恢复正确的行为。

对于出现问题的任何建议都会非常感激。

1 个答案:

答案 0 :(得分:6)

Random类不是线程安全的 如果您同时在多个线程上的同一实例上生成随机数,则其内部状态将被破坏,并且它将开始返回零。

您需要创建Random实例[ThreadStatic]以确保每个实例不被多个线程共享。
请注意,[ThreadStatic]字段的初始值设定项只会运行一次,因此每次使用该字段时都需要检查它是否null并在必要时进行初始化。
在种子中包含线程ID和当前时间以防止种子冲突也是一个好主意。

请注意,Random类不安全;考虑使用RNGCryptoServiceProvider class