# Ubuntu上使用C++ muliti - thread筆記
參考
jyt0532's Blog - Introduction to C++ multithread
https://hackmd.io/9oWkdjdHRMCqzOBwEI5waA?view#lock_guard
## compile(in C++11
```
$ g++ filename.cpp -o filename -l pthread
```
## 使用
先`#include <thread>`
寫一個void function
在thread後面呼叫
```cpp
void thread_func(){
/*~~~~*/
}
int main (){
/*~~~~~*/
thread t1(thread_func); //thread會在這裡一呼叫就開始執行,不用等到join
t1.join(); //再t1結束之後才可以跑main,否則會abort
t1.detach(); //或是可以使用detach,不用等t1結束就可以繼續執行
}
```
### 傳值與vector
(懶得說明了
```cpp=
#include <thread>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void func(int i, string s)
{
cout << i << ", " << this_thread::get_id() << endl;
}
int main()
{
vector<thread> threads;
for(int i = 0; i < 10; i++){
threads.push_back(thread(func, i, "test")); //我試過用看看array但是我不會
}
for(int i = 0; i < threads.size(); i++){
cout << threads[i].get_id() << endl;
threads[i].join();
}
return 0;
}
```
#### ref()是森摸
也是在C++11中的用法,會把值存回main裡的那個值
```cpp
#include <thread>
#include <iostream>
using namespace std;
void func(int a,int &b){
a = 100;b = 200;
}
int main(){
int a = 1,b = 2;
thread t(func,a,ref(b));
t.join();
cout<<"a "<<a<<" b "<< b<<endl;
return 0;
}
```
輸出結果
`a 1 b 200`
### lock
在使用thread的時候要注意shared memory會不會爆掉
#### 陽春lock
使用mutex
要`#include <mutex>`
```cpp=
#include <thread>
#include <iostream>
#include <string>
#include <vector>
#include <mutex>
using namespace std;
//把mutex和要用的sum包在一起到struct裡面,因為用global variable容易出錯
struct Sum{
int sum = 0;
mutex mu;
//使用前lock,用完unlock
void incre(){
mu.lock();
sum++;
mu.unlock();
}
};
void func(Sum &s)
{
s.incre();
}
int main()
{
vector<thread> threads;
Sum s;
for(int i = 0; i < 10000; i++){
threads.push_back(thread(func, ref(s)));
}
for(int i = 0; i < threads.size(); i++){
threads[i].join();
}
cout << s.sum << endl;
return 0;
}
```
如果在lock and unlock中間有錯誤的話,就有可能會永遠無法unlock
可以把中間過程改成try
```cpp=
m.lock();
try{
funA(); //可能會出錯的地方
} catch(std::exception &cException){
m.unlock();
throw cException;
}
m.unlock();
```
(看後面stack unwinding)
如果中間有很多exception就有可能無法好好release lock(因為unlock可能還來不及執行,程式就被destruct了)
利用在construct和destruct 的時候分配好lock去避免
可以用lock_guard或unique_lock比較方便
#### lock_guard
直接在要執行的thread中使用,但是仍然要先宣告mutex,解構的時候自動unlock
```cpp=
mutex m;
void thread(){
lock_guard<mutex> lg(m); //lg是自己設定的名字
/*~~~~~~~~*/
}
```
#### unique_lock
也是解構時自動解鎖
很多功能...
可以參考
https://www.twblogs.net/a/5b7dc7612b7177285fcb27dd
https://www.itread01.com/content/1546066929.html
https://www.itread01.com/content/1544658362.html
```cpp=
mutex m1,m2,m3;
void thread(){
//(unique_lock...都是初始化一個新的lock然後對某lock操作,這裡是m)
unique_lock<mutex> lock1(m1,try_to_lock); //嘗試加鎖 = m.try_lock()
unique_lock<mutex> lock2(m2,defer_lock); //在建構時"先"不執行m2.lock()
unique_lock<mutex> lock3(m3,adopt_lock); //直接lock
/*~~~~~~~~*/
}
```
#### 插播:stack unwinding
是指如果在try的過程中發生exception(自己throw出來),就會直接destruct原本在執行的東西跳出來到catch的地方,之後的Code就不管了,但是會執行destructor
### condition variable
要`#include <condition_variable>`
當作一個queue來放要排隊的thread
功能
```cpp=
condition_variable cv; //declare
mutex m;
void thread(){
unique_lock<mutex> ul(m);
cv.wait(ul) //這個thread被放cv queue中,會自己unlock
cv.notify_one() //叫醒cv queue中的第一個thread
cv.notify_all() //叫醒所有cv queue中的thread
/*~~~~~~~~~~~~*/
}
```
小截範例
```cpp=
int thread(){
unique_lock<mutex> lk(lock);
while(true){
cv1.wait(lk);
}
/*~~~~*/
lk.unlock();
cv2.notify_one();
/*~~~~*/
return;
}
```
在while裡面叫wait的情形,這個thread會直接跳到cv queue中睡覺(不會待在while裡面跑),等到再次被喚醒時從頭(unique_lock....那裡)開始執行