代码之家  ›  专栏  ›  技术社区  ›  relatively_random

锁顺序一致吗?

  •  0
  • relatively_random  · 技术社区  · 7 年前

    这是这个问题的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 回复  |  直到 7 年前
        1
  •  2
  •   Gerald Chifanzwa    7 年前

    锁不能保证顺序一致性。相反,它保证如果一个线程在需要一组资源的情况下启动一个操作,那么在带有锁的线程使用资源之前,没有其他线程可以访问(和更改)这些资源。哪个线程首先尝试访问资源取决于一大堆锁实际上并不关心的其他因素。

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

    看到了吗 lock statement documentation

        2
  •  1
  •   Matthew Watson    7 年前

    要查看这在理论上是否可以返回(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)
    

    这证明了这一点 理论上 可能会返回顺序错误的结果。