【发布时间】:2018-10-31 09:18:00
【问题描述】:
这是这个问题的 C# 版本:Is std::mutex sequentially consistent?
简而言之:如果多个线程对不同的对象进行锁定,它们是否保证在这些不同的锁定中看到相同的事件顺序?
这里是演示:
internal sealed class Test
{
private readonly object lockerA = new object();
private bool valueA;
private readonly object lockerB = new object();
private bool valueB;
public void RunTest()
{
var taskA = Task.Run(() =>
{
lock (lockerA)
valueA = true;
});
var taskB = Task.Run(() =>
{
lock (lockerB)
valueB = true;
});
var taskC = Task.Run(() =>
{
// Reads A, then B.
bool readA;
lock (lockerA)
readA = valueA;
bool readB;
lock (lockerB)
readB = valueB;
return (readA, readB);
});
var taskD = Task.Run(() =>
{
// Reads B, then A.
bool readB;
lock (lockerB)
readB = valueB;
bool readA;
lock (lockerA)
readA = valueA;
return (readA, readB);
});
Task.WaitAll(taskA, taskB, taskC, taskD);
if (taskC.Result == (readA:true, readB:false) && taskD.Result == (readA:false, readB:true))
{
// Can this happen?
Console.WriteLine("Ordering inconsistency!");
}
}
}
编辑:
修复了Matthew Watson 显示示例即使具有顺序一致性也失败后的错误。
【问题讨论】:
-
需要注意的一点是
bool的赋值是原子操作,由于您只是锁定bool的赋值,因此锁定实际上没有任何好处。完全没有任何锁,代码也能正常工作。 -
我的意思是锁对你想要的原子操作没有帮助,也就是说,设置 A 和 B 并读取 A 和 B。要做到这一点,您必须锁定读取和写入这两个变量的代码。
-
我在您的other question 上发布的涵盖执行顺序的 C# 规范部分就是关于 C# 重新排序的讨论。在引用的部分省略中,它还讨论了
lock。 -
即使特定平台上的当前行为碰巧是“连续的”,我可以告诉你,规范中并不能保证它,因此 a) 取决于实施和 b) 可能会发生变化。我显然知道代码不实用,如果您依赖于避免您描述为“不一致”的行为,那么将其扩展到任何实用代码都是一种糟糕的设计模式。例如,它在 ARM、Mono、.NET vNext 或 Intel 芯片 vNext 上的行为可能有所不同。
-
@MikeMarynowski “即使特定平台上的当前行为恰好是“连续的”,我可以告诉你,规范中并不能保证这一点”这就是被问到的问题。所有其他 cmets 都是关于我应该或不应该编写什么样的代码的不必要的和题外话的讨论。
标签: c# multithreading thread-safety language-lawyer