Нужно ли добавлять дополнительный забор в эту реализацию алгоритмов Деккера? - PullRequest
0 голосов
/ 13 апреля 2020

Я изучаю алгоритмы Деккера, просматривая код из этого блога и код выглядит следующим образом:

    std::atomic<bool> flag0(false),flag1(false);
    std::atomic<int> turn(0);

    void p0()
    {
        flag0.store(true,std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_seq_cst);

        while (flag1.load(std::memory_order_relaxed))
        {
            if (turn.load(std::memory_order_relaxed) != 0)
            {
                flag0.store(false,std::memory_order_relaxed);
                // --------------------------------------------------------------------
                // Is it need to add a memory fence here to prevent storing `false` to flag0 from 
                // reordering after the while loop waiting for turn?
                // ---------------------------------------------------------------------
                while (turn.load(std::memory_order_relaxed) != 0)
                {
                }
                //
                // Any chances flag0.store() be reordered here ? 
                //

                flag0.store(true,std::memory_order_relaxed);
                std::atomic_thread_fence(std::memory_order_seq_cst);
            }
        }
        std::atomic_thread_fence(std::memory_order_acquire);

        // critical section


        turn.store(1,std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_release);
        flag0.store(false,std::memory_order_relaxed);
    }

    void p1()
    {
        flag1.store(true,std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_seq_cst);

        while (flag0.load(std::memory_order_relaxed))
        {
            if (turn.load(std::memory_order_relaxed) != 1)
            {
                flag1.store(false,std::memory_order_relaxed);
                // --------------------------------------------------------------------
                // Is it need to add a memory fence here to prevent storing `false` to flag0 from 
                // reordering after the while loop waiting for turn?
                // ---------------------------------------------------------------------
                while (turn.load(std::memory_order_relaxed) != 1)
                {
                }
                //
                // Any chances flag1.store() be reordered here ? 
                //

                flag1.store(true,std::memory_order_relaxed);
                std::atomic_thread_fence(std::memory_order_seq_cst);
            }
        }
        std::atomic_thread_fence(std::memory_order_acquire);

        // critical section


        turn.store(0,std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_release);
        flag1.store(false,std::memory_order_relaxed);
    }

Необходимо ли добавить некоторый забор памяти между

flag0.store(false,std::memory_order_relaxed);

И

while (turn.load(std::memory_order_relaxed) != 0) {}?

Я не уверен, есть ли вероятность того, что компилятор переупорядочит сохранение в flag0 и пока l oop в ожидании turn. Если это так, то в случае, когда поток 0 и поток 1 вводят p0 и p1, соответственно, с flag0 и flag1, установленными в true, одновременно, поток 0 может зависать при ожидании установки flag1 на false, а поток 1 может зависать ожидание бесконечной установки turn на 1, что приводит к мертвой блокировке.

...