锁是否顺序一致?

时间:2018-10-31 09:18:00

标签: c# multithreading thread-safety language-lawyer

这是此问题的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之后的错误,该错误表明示例即使具有顺序一致性也失败了。

2 个答案:

答案 0 :(得分:2)

锁不保证顺序一致性。相反,它保证了如果线程在需要一组资源的情况下启动操作,则其他线程无法访问(或更改)这些资源,直到拥有锁的线程对资源进行处理为止。哪个线程首先尝试访问资源受制于锁实际上并不关心的许多其他因素。

在要确保对象在操作期间不会被其他线程修改的操作中使用锁。哪个操作首先访问线程-那就是一个完全不同的故事。

请参见lock statement documentation

答案 1 :(得分:1)

要查看从理论上讲这是否可以返回(false,true)和(true,false),我们只需要显示一组交错的步骤,任务就可以从理论上执行该结果。

这是一组步骤:

Init: A = false, B = false

Task A: starting up
Task B: starting up
Task C: enter lock A
Task C: read A = false   C.A = false
Task C: leave lock A
Task A: enter lock A
Task A: set A = true     A = true
Task A: leave lock A
Task A: exit
Task D: enter lock B
Task D: read B = false   D.B = false
Task D: leave lock B
Task B: enter lock B
Task B: set B = true     B = true
Task B: leave lock B
Task B: exit
Task C: enter lock B
Task C: read B = true    C.B = true
Task C: leave lock B
Task C: exit returning (false, true)
Task D: enter lock A
Task D: read A = true    D.A = true
Task D: leave lock A
Task D: exit returning (true, false)

Now task C returned (false, true) and task D returned (true, false)

证明理论上可以返回不合序列的结果。