的文档lock https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement声明非常简单:
lock (x)
{
// Your code...
}
其中 x 是 a 的表达式参考类型.
所以我不应该被允许传递一个值类型作为储物柜lock
。我注意到我可以使用实现接口的值类型。换句话说,我可以这样做:
IDisposable locker = default(DisposableStruct);
lock (locker) Console.WriteLine("Thread safe");
struct DisposableStruct : IDisposable
{
public void Dispose() { }
}
这很令人惊讶。我发现原因是值类型被装箱了。根据文档 https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing:
装箱是将值类型转换为类型的过程object
, or to 任何接口类型由该值类型实现。
我的问题是,使用盒装值类型作为储物柜是否有任何警告lock
陈述。引用类型包装器是否有可能在程序执行过程中以某种方式发生变化,从而导致线程安全代码失败?
Update:这是一个让我担心的例子。是否保证如果我运行代码一百万次,总是会显示正确的输出(1,000,000,000)?
IComparable<int> boxedValueType = 0;
int sharedState = 0;
var tasks = Enumerable.Range(0, 10).Select(_ => Task.Run(() =>
{
for (int i = 0; i < 100_000_000; i++)
lock (boxedValueType)
sharedState++;
})).ToArray();
Task.WaitAll(tasks);
Console.WriteLine(sharedState);