Massive CPU load using std::lock (c++11)

前端 未结 4 992
梦毁少年i
梦毁少年i 2020-12-07 15:09

My recent efforts to implement a thread/ mutex manager ended up in an 75% CPU load (4 core), while all four running threads were either in sleep or waiting for a mutex beein

4条回答
  •  天涯浪人
    2020-12-07 15:32

    On my machine, the following code prints out 10 times a second and consumes almost 0 cpu because most of the time the thread is either sleeping or blocked on a locked mutex:

    #include 
    #include 
    #include 
    #include 
    
    using namespace std::chrono_literals;
    
    std::mutex m1;
    std::mutex m2;
    
    void
    f1()
    {
        while (true)
        {
            std::unique_lock l1(m1, std::defer_lock);
            std::unique_lock l2(m2, std::defer_lock);
            std::lock(l1, l2);
            std::cout << "f1 has the two locks\n";
            std::this_thread::sleep_for(100ms);
        }
    }
    
    void
    f2()
    {
        while (true)
        {
            std::unique_lock l2(m2, std::defer_lock);
            std::unique_lock l1(m1, std::defer_lock);
            std::lock(l2, l1);
            std::cout << "f2 has the two locks\n";
            std::this_thread::sleep_for(100ms);
        }
    }
    
    int main()
    {
        std::thread t1(f1);
        std::thread t2(f2);
        t1.join();
        t2.join();
    }
    

    Sample output:

    f1 has the two locks
    f2 has the two locks
    f1 has the two locks
    ...
    

    I'm running this on OS X and the Activity Monitor application says that this process is using 0.1% cpu. The machine is a Intel Core i5 (4 core).

    I'm happy to adjust this experiment in any way to attempt to create live-lock or excessive cpu usage.

    Update

    If this program is using excessive CPU on your platform, try changing it to call ::lock() instead, where that is defined with:

    template 
    void
    lock(L0& l0, L1& l1)
    {
        while (true)
        {
            {
                std::unique_lock u0(l0);
                if (l1.try_lock())
                {
                    u0.release();
                    break;
                }
            }
            std::this_thread::yield();
            {
                std::unique_lock u1(l1);
                if (l0.try_lock())
                {
                    u1.release();
                    break;
                }
            }
            std::this_thread::yield();
        }
    }
    

    I would be interested to know if that made any difference for you, thanks.

    Update 2

    After a long delay, I have written a first draft of a paper on this subject. The paper compares 4 different ways of getting this job done. It contains software you can copy and paste into your own code and test yourself (and please report back what you find!):

    http://howardhinnant.github.io/dining_philosophers.html

提交回复
热议问题