c++ —多線程學習(持續更新中…)
目錄
0.聲明
我只是知識的搬運工,謝謝!
1.線程的三種啓動方式
(當然前提是要引用頭文件)
(1)普通函數啓動
#include <thread>
void function(){
//...一些操作;
}
int main(){
//這裏的function是自己定義的一個函數;這裏的參數是function的傳參。
thread myobj(function, 參數);
myobj.join();
}
(2)類中成員函數做線程啓動函數
class A{
public:
void myprint(){ //成員函數
//...一些操作
}
}
int main(){
A a;
std::thread myobj(&A::myprint, &a , 參數);
myobj.join();
}
(3)lammda表達式
auto lamthread = []{ cout << "..." << endl;....}
thread a(lamthread);
a.join();
2.使用detach()時注意事項
.*detach()與.join()區別在於後者是主線程等待子線程結束之後在結束,而前者.detach()*則不同,此時主線程不會等待子線程結束。
在傳遞類對象時,避免隱式轉換,要在main函數中提前顯示轉換,然後在函數參數裏,用引用來接,否則系統還會多構造一次對象。
若傳遞int 這種簡單型參數,建議都是值傳遞,不要用引用。
3.創建和等待多個線程
void myprint(int i){//...}//線程函數公共入口
int main(){
vector <thread> mythreads;//線程型容器
for(int i = 0; i <= 10; ++i){
mythreads.push_back(thread(myprint , i));
}
for(auto iter = mythread.begin(); iter < mythread.end(); ++iter){
iter->join();//主線程等待所有子線程結束之後運行結束
}
cout << "主線程完畢" << endl;
return 0;
}
4.互斥量與死鎖問題及其解決方法
(1)互斥量
當同時有多個線程共享數據時,必須考慮互斥量問題。
互斥量即“鎖頭”。
當一個線程訪問並操作共享數據時必須先保護線程中操作共享數據的代碼(即上鎖),其他線程等待此線程操作完後(即開鎖後),才能對共享數據做相應的操作。
這裏通過引用頭文件#include 中的lock()和unlock()方法進行所謂的開解鎖操作。
(注意:lock(),unlock()必須成對出現)
舉例代碼:
class A{
private:
list <int> date;
mutex my_mutex;
public:
void in(int i){
my_mutex.lock();
date.push_back(i);
my_mutex.unlock();
}
void out (int command){
my_mutex.lock();
if(!date.empty())
{
command = date.front();
date.pop_front();//移除首個數據
my_mutex.unlock();
return true;
}
my_mutex.unlock();
return false;
}
}
(2)死鎖問題及其解決方法
死鎖問題造成的原因:
多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放,而該資源又被其他線程鎖定,從而導致每一個線程都得等其它線程釋放其鎖定的資源,造成了所有線程都無法正常結束。
死鎖問題必須是兩個及兩個以上互斥量(鎖),兩個及兩個以上的線程。
舉例說明:
現有兩把鎖:my_mutex1,my_mutex2
第一種方案:兩把鎖上鎖順序一致,即第一條線程中my_mutex1.lock();和my_mutex2.lock();是什們前後位置,在別的線程中就應該是什麼順序。代碼簡寫:
#include<mutex>
{
mutex my_mutex1;//聲明互斥量1(即鎖)
mutex my_mutex2;//聲明互斥量2(即鎖)
一個線程中:
my_mutex1.lock();
//一些操作
my_mutex2.lock();
//要保護的代碼操作塊
my_mutex1.unlock();
my_mutex2.unlock();
另一線程中:
my_mutex1.lock();
//一些操作
my_mutex2.lock();
//要保護的代碼操作塊
my_mutex1.unlock();
my_mutex2.unlock();
}
第二種方案:運用lock_guard類模板。
lock_guard類模板原理在於,它將lock()寫入構造函數,將unlock()寫入析構函數中。
std::lock_guardstd::mutex a(my_mutex);
代碼簡寫:
#include<mutex>
{
mutex my_mutex1;//聲明互斥量1(即鎖)
mutex my_mutex2;//聲明互斥量2(即鎖)
一個線程中:
std::lock_guard<std::mutex> a1(my_mutex1);
std::lock_guard<std::mutex> a2(my_mutex2);
//要保護的代碼操作塊
另一線程中:
std::lock_guard<std::mutex> a1(my_mutex1);
std::lock_guard<std::mutex> a2(my_mutex2);
//要保護的代碼操作塊
}
第三種方案:運用std::lock()函數模板,和std::lockguard類模板
(std::lock()函數模板把不經常用,一般兩個互斥量之間應該有一些操作,建議一個一個鎖)
#include<mutex>
{
mutex my_mutex1;//聲明互斥量1(即鎖)
mutex my_mutex2;//聲明互斥量2(即鎖)
一個線程中:
std::lock(my_mutex1,my_mutex2);
std::lock_guard<std::mutex> a1(my_mutex1,std::adopt_lock);
//std::adopt_lock是一個結構體對象,起標記作用。
//作用就是這個互斥量已經lock()過了就不需要在std::lock_guard<std::mutex>裏面對對//象進行再次的lock()了。
std::lock_guard<std::mutex> a2(my_mutex2,std::adopt_lock);
//要保護的代碼操作塊
另一線程中:
std::lock(my_mutex1,my_mutex2);
std::lock_guard<std::mutex> a1(my_mutex1,std::adopt_lock);
std::lock_guard<std::mutex> a2(my_mutex2,std::adopt_lock);
//要保護的代碼操作塊
}
自學過程中雜碎cpp知識
(1)list:對頻繁地按順序插入和刪除數據是效率高;vector:對隨機的插入和刪除數據的效率高
(2)使用std::ref()時,說明我們告訴控制檯必須要用原來沒有拷貝的初始值來做傳遞,並且此時函數中的參數前不在加const。(聲明線程時,括號中&myobj == std::ref(myobj),即第二個參數是引用,才能保證線程裏用的是同一對象)
(3)傳遞智能指針時,用std::move()(把智能指針移到參數中,原先的智能指針指向爲空,所以,main中只能用join不能用detach)
Finally Self-introduction
歡迎光臨我的博客瞭解更多