互斥量概念,用法,死鎖演示及解決詳解
阿新 • • 發佈:2018-12-21
保護共享資料,用程式碼把共享資料鎖住,其他想操作共享資料的執行緒得等待解鎖。
互斥量的概念:
互斥量是個類物件。多個執行緒嘗試lock鎖上。結果:只有一個執行緒能夠鎖定成功,成功的標誌是lock函式返回。如果沒鎖成功,那麼流程就會卡在lock這,不斷嘗試去鎖,一直到成功。
互斥量使用起來要小心,保護資料不要多也不要少,少了程式該崩潰還是崩潰,多了影響程式的執行效率。
互斥量的用法:
標頭檔案
#include<mutex>//互斥量
步驟:先lock(),操作共享資料,unlock();
lock()和unlock()要成對使用。
static int num_push = 0; static int num_pop = 0; class A { std::list<int>msgReceive; std::mutex my_mutex;//建立一個互斥量的成員變數 public: void inMsgRecQueue() { for (int i = 0; i < 100; ++i) { cout << ++num_push << endl; my_mutex.lock(); msgReceive.push_back(i); my_mutex.unlock(); } } bool booloutMsg(int &commend) { my_mutex.lock(); if (!msgReceive.empty()) { cout << ++num_pop << endl; //訊息不為空 int commend = msgReceive.front(); msgReceive.pop_front(); my_mutex.unlock(); //...其他處理 return true; } cout << ++num_pop << endl; my_mutex.unlock(); return false; } void outMsgRecQuene() { int commend = 0; for (int i = 0; i < 100; ++i) { bool result = booloutMsg(commend); if (result==true) { //成功處理 } else { //訊息為空 cout << "outMsgRecQuene執行,但是訊息佇列為空!" << endl; } } } }; int main() { A a; std::thread myOutMsg(&A::outMsgRecQuene, &a); std::thread myRecMsg(&A::inMsgRecQueue, &a); myOutMsg.join(); myRecMsg.join(); cout << "num_push = " << num_push << endl << "num_pop = " << num_pop << endl; return 0; }
std::lock_guard<mutex> text<my_mutex>
建構函式裡執行了mutex的lock(),解構函式裡執行了mutex的unlock()。
但是不太靈活,必須要等解構函式執行才會解鎖。
lock_guard例項
static int num_push = 0; static int num_pop = 0; class A { std::list<int>msgReceive; std::mutex my_mutex;//建立一個互斥量的成員變數 public: void inMsgRecQueue() { for (int i = 0; i < 100; ++i) { cout << ++num_push << endl; std::lock_guard<mutex> test_lock(my_mutex); msgReceive.push_back(i); } } bool booloutMsg(int &commend) { std::lock_guard<mutex> test_lock(my_mutex); if (!msgReceive.empty()) { cout << ++num_pop << endl; //訊息不為空 int commend = msgReceive.front(); msgReceive.pop_front(); //...其他處理 return true; } cout << ++num_pop << endl; return false; } void outMsgRecQuene() { int commend = 0; for (int i = 0; i < 100; ++i) { bool result = booloutMsg(commend); if (result==true) { //成功處理 } else { //訊息為空 cout << "outMsgRecQuene執行,但是訊息佇列為空!" << endl; } } } }; int main() { A a; std::thread myOutMsg(&A::outMsgRecQuene, &a); std::thread myRecMsg(&A::inMsgRecQueue, &a); myOutMsg.join(); myRecMsg.join(); cout << "num_push = " << num_push << endl << "num_pop = " << num_pop << endl; return 0; }
死鎖
產生的前提條件:是由至少兩個互斥量才會產生這個問題。
static int num_push = 0; static int num_pop = 0; class A { std::list<int>msgReceive; std::mutex my_mutex1,my_mutex2;//建立一個互斥量的成員變數 public: void inMsgRecQueue() { for (int i = 0; i < 100; ++i) { cout << ++num_push << endl; my_mutex1.lock(); my_mutex2.lock(); msgReceive.push_back(i); my_mutex2.unlock(); my_mutex1.unlock(); } } bool booloutMsg(int &commend) { my_mutex2.lock(); my_mutex1.lock(); if (!msgReceive.empty()) { cout << ++num_pop << endl; //訊息不為空 int commend = msgReceive.front(); msgReceive.pop_front(); //...其他處理 my_mutex2.unlock(); my_mutex1.unlock(); return true; } my_mutex2.unlock(); my_mutex1.unlock(); cout << ++num_pop << endl; return false; } void outMsgRecQuene() { int commend = 0; for (int i = 0; i < 100; ++i) { bool result = booloutMsg(commend); if (result==true) { //成功處理 } else { //訊息為空 cout << "outMsgRecQuene執行,但是訊息佇列為空!" << endl; } } } }; int main() { A a; std::thread myOutMsg(&A::outMsgRecQuene, &a); std::thread myRecMsg(&A::inMsgRecQueue, &a); myOutMsg.join(); myRecMsg.join(); cout << "num_push = " << num_push << endl << "num_pop = " << num_pop << endl; return 0; }
一般解決方案:只要順序不搞亂,就不會出現死鎖。
std::lock()函式模板:兩個互斥量的時候才使用
要麼兩個互斥量都鎖住,要麼兩個互斥量都沒鎖住。
static int num_push = 0;
static int num_pop = 0;
class A {
std::list<int>msgReceive;
std::mutex my_mutex1,my_mutex2;//建立一個互斥量的成員變數
public:
void inMsgRecQueue()
{
for (int i = 0; i < 100; ++i)
{
cout << ++num_push << endl;
std::lock(my_mutex1, my_mutex2);
msgReceive.push_back(i);
my_mutex2.unlock();
my_mutex1.unlock();
}
}
bool booloutMsg(int &commend)
{
std::lock(my_mutex1, my_mutex2);
if (!msgReceive.empty())
{
cout << ++num_pop << endl;
//訊息不為空
int commend = msgReceive.front();
msgReceive.pop_front();
//...其他處理
my_mutex2.unlock();
my_mutex1.unlock();
return true;
}
my_mutex2.unlock();
my_mutex1.unlock();
cout << ++num_pop << endl;
return false;
}
void outMsgRecQuene()
{
int commend = 0;
for (int i = 0; i < 100; ++i)
{
bool result = booloutMsg(commend);
if (result==true)
{
//成功處理
}
else
{
//訊息為空
cout << "outMsgRecQuene執行,但是訊息佇列為空!" << endl;
}
}
}
};
int main()
{
A a;
std::thread myOutMsg(&A::outMsgRecQuene, &a);
std::thread myRecMsg(&A::inMsgRecQueue, &a);
myOutMsg.join();
myRecMsg.join();
cout << "num_push = " << num_push << endl
<< "num_pop = " << num_pop << endl;
return 0;
}
std::lock_guard<mutex> test(my_mutex1, std::adopt_lock);
表示之前已經鎖過了。
static int num_push = 0;
static int num_pop = 0;
class A {
std::list<int>msgReceive;
std::mutex my_mutex1,my_mutex2;//建立一個互斥量的成員變數
public:
void inMsgRecQueue()
{
for (int i = 0; i < 100; ++i)
{
cout << ++num_push << endl;
std::lock(my_mutex1, my_mutex2);
std::lock_guard<mutex> test(my_mutex1, std::adopt_lock);
std::lock_guard<mutex> test1(my_mutex2, std::adopt_lock);
msgReceive.push_back(i);
}
}
bool booloutMsg(int &commend)
{
std::lock(my_mutex1, my_mutex2);
std::lock_guard<mutex> test(my_mutex1, std::adopt_lock);
std::lock_guard<mutex> test1(my_mutex2, std::adopt_lock);
if (!msgReceive.empty())
{
cout << ++num_pop << endl;
//訊息不為空
int commend = msgReceive.front();
msgReceive.pop_front();
//...其他處理
return true;
}
cout << ++num_pop << endl;
return false;
}
void outMsgRecQuene()
{
int commend = 0;
for (int i = 0; i < 100; ++i)
{
bool result = booloutMsg(commend);
if (result==true)
{
//成功處理
}
else
{
//訊息為空
cout << "outMsgRecQuene執行,但是訊息佇列為空!" << endl;
}
}
}
};
int main()
{
A a;
std::thread myOutMsg(&A::outMsgRecQuene, &a);
std::thread myRecMsg(&A::inMsgRecQueue, &a);
myOutMsg.join();
myRecMsg.join();
cout << "num_push = " << num_push << endl
<< "num_pop = " << num_pop << endl;
return 0;
}