#include "stdafx.h"
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<thread>
using namespace std;
void myprint(int num){
cout << "子線程開始執行,子線程編號=" << num << endl;
cout << "子線程結束執行,子線程編號=" << num << endl;
}
vector<int>global_v = { 1,2,3 };
int main()
{
vector<thread>mythreads;
for (int i = 0; i < 10; i++)
{
mythreads.push_back(thread(&myprint,i));//創建10個子線程,每個子線程的入口函數統一爲myprint
}
for (auto it = mythreads.begin(); it!=mythreads.end(); it++)
{
it->join();//等待10個子線程都返回
}
cout << "主線程結束執行" << endl;
system("pause");
return 0;
}
多線程中,多個線程對共享的數據進行訪問,應該是最常見的應用。
如果多個線程都只是對共享數據進行讀操作,還不會有問題,但是如果有的線程讀數據,有的線程寫數據,這時候就會出現問題。比如A線程寫數據,但是寫的這個過程進行到一半,B線程就去讀,這個時候程序就會崩潰。這個時候就需要互斥量的出場啦!
mutex
解決方案如下:
#include "stdafx.h"
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<thread>
#include<list>//雙向鏈表
#include<mutex>
#include <deque>
using namespace std;
class A
{
public:
//把收到的消息(假設是一個int型整數)放到一個隊列的子線程函數
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()執行,插入一個元素" << i << endl;
//my_mutex.lock();
lock_guard<mutex>my_guard(my_mutex);
msgRecvQueue.push_back(i);
//my_mutex.unlock();
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
my_mutex.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
cout << "outMsgRecvQueue()執行,取出一個元素" << command << endl;
}
else
{
my_mutex.unlock();
cout << "outMsgRecvQueue()執行,但隊列爲空" << endl;
}
}
}
private:
list<int>msgRecvQueue;//消息隊列,list、deque均可
mutex my_mutex;//創建一個互斥量成員變量
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "主線程結束執行" << endl;
system("pause");
return 0;
}
注意事項:
1.mutex的成員函數lock()和unlock()必須同時成對出現,否則必完蛋。
2.如果使用lock_guard,就類似智能指針的用法,當lock_guard的對象生命週期結束時,會調用析構函數,而在析構函數中實際是調用了unlock()。
3.一旦使用了lock_guard,同一個地方就不能再使用lock()和unlock()。
std::lock()函數模板
std::lock()用來處理多個互斥量的時候纔出場;
能力:一次鎖住兩個或兩個以上的互斥量;
它可以避免在多個線程中,因爲鎖的順序問題導致出現死鎖的風險。
std::lock():如果互斥量中一個沒鎖住,子線程就阻塞,等到所有的互斥量都鎖住,子線程才能往下走。即要麼兩個互斥量都鎖住,要麼兩個互斥量都沒鎖住,如果只鎖了一個,另外一個沒鎖成功,則它立即把已經鎖住的互斥量解鎖。
先放一個因爲鎖的順序問題導致出現死鎖的例子:
class A
{
public:
//把收到的消息(假設是一個int型整數)放到一個隊列的子線程函數
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()執行,插入一個元素" << i << endl;
my_mutex1.lock();
my_mutex2.lock();
msgRecvQueue.push_back(i);
my_mutex1.unlock();
my_mutex2.unlock();
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
my_mutex2.lock();
my_mutex1.lock();
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex1.unlock();
my_mutex2.unlock();
cout << "outMsgRecvQueue()執行,取出一個元素" << command << endl;
}
else
{
my_mutex1.unlock();
my_mutex2.unlock();
cout << "outMsgRecvQueue()執行,但隊列爲空" << endl;
}
}
}
private:
list<int>msgRecvQueue;//消息隊列,list、deque均可
mutex my_mutex1;//創建一個互斥量成員變量
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "主線程結束執行" << endl;
system("pause");
return 0;
}
使用std::lock()解決方案如下:
class A
{
public:
//把收到的消息(假設是一個int型整數)放到一個隊列的子線程函數
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()執行,插入一個元素" << i << endl;
lock(my_mutex1, my_mutex2);
msgRecvQueue.push_back(i);
my_mutex1.unlock();
my_mutex2.unlock();
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
lock(my_mutex1,my_mutex2);
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex1.unlock();
my_mutex2.unlock();
cout << "outMsgRecvQueue()執行,取出一個元素" << command << endl;
}
else
{
my_mutex1.unlock();
my_mutex2.unlock();
cout << "outMsgRecvQueue()執行,但隊列爲空" << endl;
}
}
}
private:
list<int>msgRecvQueue;//消息隊列,list、deque均可
mutex my_mutex1;//創建一個互斥量成員變量
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "主線程結束執行" << endl;
system("pause");
return 0;
}
std::lock_guard的std::adopt_lock參數
std::adopt_lock是個結構體對象,起一個標記作用:作用是表示這個互斥量已經執行過lock()了,不需要在lock_guard<mutex>
構造函數裏面再對mutex的對象進行lock()了。
class A
{
public:
//把收到的消息(假設是一個int型整數)放到一個隊列的子線程函數
void inMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
cout << "inMsgRecvQueue()執行,插入一個元素" << i << endl;
lock(my_mutex1, my_mutex2);
lock_guard<mutex>my_guard1(my_mutex1,adopt_lock);
lock_guard<mutex>my_guard2(my_mutex2, adopt_lock);
msgRecvQueue.push_back(i);
}
}
void outMsgRecvQueue()
{
for (int i = 0; i < 100000; i++)
{
lock(my_mutex1,my_mutex2);
lock_guard<mutex>my_guard1(my_mutex1, adopt_lock);
lock_guard<mutex>my_guard2(my_mutex2, adopt_lock);
if (!msgRecvQueue.empty())
{
int command = msgRecvQueue.front();
msgRecvQueue.pop_front();
cout << "outMsgRecvQueue()執行,取出一個元素" << command << endl;
}
else
{
cout << "outMsgRecvQueue()執行,但隊列爲空" << endl;
}
}
}
private:
list<int>msgRecvQueue;//消息隊列,list、deque均可
mutex my_mutex1;//創建一個互斥量成員變量
mutex my_mutex2;
};
int main()
{
A myobja;
thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);
thread myInMsgObj(&A::inMsgRecvQueue, &myobja);
myInMsgObj.join();
myOutMsgObj.join();
cout << "主線程結束執行" << endl;
system("pause");
return 0;
}