---
# System prepended metadata

title: Ubuntu上使用C++ muliti - thread筆記

---

# 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....那裡）開始執行

