1. 程式人生 > 實用技巧 >C++多執行緒死鎖

C++多執行緒死鎖

死鎖問題被認為是執行緒/程序間切換消耗系統性能的一種極端情況。在死鎖時,執行緒/程序間相互等待資源,而又不釋放自身的資源,導致無窮無盡的等待,其結果是任務永遠無法執行完成。

死鎖出現的場景:當代碼中有2個鎖,鎖A和鎖B,也有2個執行緒,執行緒1和執行緒2,執行緒1執行時,先搶到鎖A,然後要去搶佔B,同時執行緒2先搶到了鎖B,然後要去搶佔鎖A,此時就出現死鎖情況,互相等待資源,又不釋放自身的資源。

如下程式碼:

#include <iostream>
#include<thread>
#include<string>
#include<vector>
#include
<algorithm> #include<windows.h> #include<list> #include<mutex> using namespace std; class myClass { public: void AddOrder() { for (int i = 0; i < 10000; i++) { cout << "addOrder執行,插入一個元素" << i << endl; m_mutex1.
lock(); m_mutex2.lock(); m_orderList.push_back(i); m_mutex1.unlock(); m_mutex2.unlock(); } } void RemoveOrder() { for (int i = 0; i < 10000; i++) { m_mutex2.lock(); m_mutex1.lock();
if (!m_orderList.empty()) { int i = m_orderList.front(); m_orderList.pop_front(); cout << "RemoveOrder執行,刪除一個元素11111111111111111111" << i << endl; } m_mutex1.unlock(); m_mutex2.unlock(); } } private: std::list<int> m_orderList; std::mutex m_mutex1; std::mutex m_mutex2; }; int main() { myClass my; std::thread obj1(&myClass::AddOrder, &my); std::thread obj2(&myClass::RemoveOrder, &my); obj1.join(); obj2.join(); system("pause"); }
View Code

解決方法:std::lock()

  std::lock()的作用是:當有2給鎖時,要麼同時鎖上,要麼同時不鎖。就是當執行緒1執行時,先搶到鎖A,然後發現鎖B被別人佔用時,此時搶不到鎖B,然後它就會把A鎖也釋放掉。

程式碼如下:

#include <iostream>
#include<thread>
#include<string>
#include<vector>
#include<algorithm>
#include<windows.h>
#include<list>
#include<mutex>

using namespace std;

class myClass
{
public:
    void AddOrder()
    {
        for (int i = 0; i < 10000; i++)
        {
            cout << "addOrder執行,插入一個元素" << i << endl;
            std::lock(m_mutex1, m_mutex2);
            m_orderList.push_back(i);
            m_mutex1.unlock();
            m_mutex2.unlock();
        }
    }

    void RemoveOrder()
    {
        for (int i = 0; i < 10000; i++)
        {
            std::lock(m_mutex2, m_mutex1);
            if (!m_orderList.empty())
            {
                int i = m_orderList.front();
                m_orderList.pop_front();
                cout << "RemoveOrder執行,刪除一個元素11111111111111111111" << i << endl;
            }
            m_mutex1.unlock();
            m_mutex2.unlock();
        }
    }

private:
    std::list<int> m_orderList;
    std::mutex m_mutex1;
    std::mutex m_mutex2;
};

int main()
{
    myClass my;

    std::thread obj1(&myClass::AddOrder, &my);
    std::thread obj2(&myClass::RemoveOrder, &my);
    obj1.join();
    obj2.join();
    
    system("pause");
}
View Code

以下是對上面程式碼優化,用到了lock_guard,防止上鎖後忘記解鎖。std::adopt_lock作用取消上鎖功能

#include <iostream>
#include<thread>
#include<string>
#include<vector>
#include<algorithm>
#include<windows.h>
#include<list>
#include<mutex>

using namespace std;

class myClass
{
public:
    void AddOrder()
    {
        for (int i = 0; i < 10000; i++)
        {
            cout << "addOrder執行,插入一個元素" << i << endl;
            std::lock(m_mutex1, m_mutex2);
            std::lock_guard<std::mutex> guard1(m_mutex1, std::adopt_lock);
            std::lock_guard<std::mutex> guard2(m_mutex2, std::adopt_lock);
            m_orderList.push_back(i);
        }
    }

    void RemoveOrder()
    {
        for (int i = 0; i < 10000; i++)
        {
            std::lock(m_mutex2, m_mutex1);
            std::lock_guard<std::mutex> guard1(m_mutex1, std::adopt_lock);
            std::lock_guard<std::mutex> guard2(m_mutex2, std::adopt_lock);
            if (!m_orderList.empty())
            {
                int i = m_orderList.front();
                m_orderList.pop_front();
                cout << "RemoveOrder執行,刪除一個元素" << i << endl;
            }
        }
    }

private:
    std::list<int> m_orderList;
    std::mutex m_mutex1;
    std::mutex m_mutex2;
};

int main()
{
    myClass my;

    std::thread obj1(&myClass::AddOrder, &my);
    std::thread obj2(&myClass::RemoveOrder, &my);
    obj1.join();
    obj2.join();
    
    system("pause");
}
View Code