Являются ли замки последовательно последовательными? - PullRequest
0 голосов
/ 31 октября 2018

Это версия C # этого вопроса: Последовательно ли std :: mutex?

Вкратце: если несколько потоков блокируют разные объекты, гарантированно ли они видят один и тот же порядок событий в этих разных блокировках?

Вот демонстрация:

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!");
        }
    }
}

EDIT:

Исправлена ​​ошибка после того, как Мэтью Уотсон показал, что пример терпит неудачу даже при последовательной согласованности.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Чтобы увидеть, может ли это теоретически возвращаться (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)

Это доказывает, что теоретически может быть возвращен несоответствующий результат.

0 голосов
/ 31 октября 2018

Замки не гарантируют последовательную последовательность. Скорее, это гарантирует, что, если поток запускает операцию, где ему требуется набор ресурсов, никакой другой поток не может получить доступ (и изменить) эти ресурсы, пока поток с блокировкой не будет сделан с ресурсами. Какой поток пытается получить доступ к ресурсам первым, зависит от целого ряда других факторов, которые на самом деле не заботятся о блокировке.

Используйте блокировки в операциях, где вы хотите гарантировать, что объект (ы) не будет изменен другими потоками во время этих операций. Какая операция сначала обращается к потоку - это совсем другая история.

См. Документацию оператора блокировки .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...