[C++11] Lockless CPU consuming on wait solution using std::atomic_flag
The solution using mutexes is trivial, however such solution does not guarantee optimal ordering. There could be a situation when only one philosopher will acqu
The solution using mutexes is trivial, however such solution does not guarantee optimal ordering. There could be a situation when only one philosopher will acquire the same resource again and again. Using more complicated aproach with conditional variables should solve the problem.\n\nThis is alternative lockeless solution with active CPU burn on resource wait. It should not suffer from resource acquisition ordering problem as much as in case of using mutexes.\n\n```\n#include <atomic>\n\n\nclass SpinLock {\npublic:\n    SpinLock() {\n        m_lock.clear();\n    }\n    \n    bool try_lock() {\n        if (!m_lock.test_and_set()) {\n            return true;\n        }\n        else {\n            return false;\n        }\n    }\n    \n\tvoid lock() {\n\t\twhile (!try_lock());\n\t}\n\n\tvoid unlock() {\n\t\tm_lock.clear();\n\t}\n\nprivate:\n\tstd::atomic_flag m_lock;\n};\n\n\nclass DiningPhilosophers {\npublic:\n    DiningPhilosophers() {\n    }\n\n\n    void wantsToEat(int philosopher,\n                    function<void()> notify_pickLeftFork,\n                    function<void()> notify_pickRightFork,\n                    function<void()> notify_eat,\n                    function<void()> notify_putLeftFork,\n                    function<void()> notify_putRightFork) {\n\t\t\n        auto forks = get_forks(philosopher);\n        \n        if (!forks.first || !forks.second) {\n            return;\n        }\n        \n        SpinLock & left_fork = *(forks.first);\n        SpinLock & right_fork = *(forks.second);\n        \n        acquire_forks(left_fork, right_fork);\n        notify_pickLeftFork();\n        notify_pickRightFork();\n        \n        notify_eat();\n        \n        release_forks(left_fork, right_fork);\n        notify_putLeftFork();\n        notify_putRightFork();\n    }\n    \nprivate:    \n    std::pair<SpinLock *, SpinLock *> get_forks(int philosopher) {\n        SpinLock * left_fork_ptr = nullptr;\n        SpinLock * right_fork_ptr = nullptr;\n        \n        switch (philosopher) {\n            case 0:\n                left_fork_ptr = &(m_forks[0]);\n                right_fork_ptr = &(m_forks[4]);\n                break;\n            case 1:\n                left_fork_ptr = &(m_forks[0]);\n                right_fork_ptr = &(m_forks[1]);\n                break;\n            case 2:\n                left_fork_ptr = &(m_forks[1]);\n                right_fork_ptr = &(m_forks[2]);\n                break;\n            case 3:\n                left_fork_ptr = &(m_forks[2]);\n                right_fork_ptr = &(m_forks[3]);                \n                break;\n            case 4:\n                left_fork_ptr = &(m_forks[3]);\n                right_fork_ptr = &(m_forks[4]);                          \n                break;\n        }\n        return std::pair<SpinLock *, SpinLock *>(left_fork_ptr, right_fork_ptr);\n    }\n    \n    void acquire_forks(SpinLock & left, SpinLock & right) {\n        while (1) {\n            if (!left.try_lock()) {\n                continue;\n            }\n            if (!right.try_lock()) {\n                left.unlock();\n                continue;\n            }\n            break;\n        }\n    }\n    \n    void release_forks(SpinLock & left, SpinLock & right) {\n        left.unlock();\n        right.unlock();\n    }    \n    \n    std::array<SpinLock, 5> m_forks;\n};\n\n```
[]