我看到我维护的一些代码存在问题。下面的代码有一个private static SHA1
成员(IDisposable
但是因为它是static
,所以它永远不会被最终确定。但是,在压力下,此代码会抛出一个异常,表明它已被关闭:
Caught exception. Safe handle has been closed"
Stack trace: Call stack where exception was thrown
at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 cbData, Int32 ibStart, Int32 cbSize)
at System.Security.Cryptography.Utils.HashData(SafeHashHandle hHash, Byte[] data, Int32 ibStart, Int32 cbSize)
at System.Security.Cryptography.HashAlgorithm.ComputeHash(Byte[] buffer)
有问题的代码是:
internal class TokenCache
{
private static SHA1 _sha1 = SHA1.Create();
private string ComputeHash(string password)
{
byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password);
return UTF8Encoding.UTF8.GetString(_sha1.ComputeHash(passwordBytes));
}
我的问题显然是可能导致此问题的原因。对SHA1.Create
的调用是否可以无声地失败(有多少加密资源可用)?这可能是appdomain发生故障造成的吗?
还有其他理论吗?
答案 0 :(得分:27)
根据HashAlgorithm
基类的the documentation
此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。
您不应该在不同线程尝试同时在同一个实例上调用ComputeHash
的线程之间共享这些类。
修改强> 这是导致您的错误的原因。由于多个线程在同一个哈希算法实例上调用ComputeHash,下面的压力测试会产生各种错误。你的错误就是其中之一。
具体来说,我在压力测试中看到了以下错误:
压力测试代码示例:
const int threadCount = 2;
var sha1 = SHA1.Create();
var b = new Barrier(threadCount);
Action start = () => {
b.SignalAndWait();
for (int i = 0; i < 10000; i++)
{
var pwd = Guid.NewGuid().ToString();
var bytes = Encoding.UTF8.GetBytes(pwd);
sha1.ComputeHash(bytes);
}
};
var threads = Enumerable.Range(0, threadCount)
.Select(_ => new ThreadStart(start))
.Select(x => new Thread(x))
.ToList();
foreach (var t in threads) t.Start();
foreach (var t in threads) t.Join();