1.建立一個線程
建立線程比較簡單,使用std的thread執行個體化一個線程對象就建立完成了,示例:
#include <iostream>
#include <thread>
using namespace std;
void t1() //普通的函數,用來執行線程
{
for (int i = 0; i < 20; ++i)
{
cout << "t1111\n";
}
}
void t2()
{
for (int i = 0; i < 20; ++i)
{
cout << "t22222\n";
}
}
int main()
{
thread th1(t1); //執行個體化一個線程對象th1,使用函數t1構造,然後該線程就開始執行了(t1())
thread th2(t2);
cout << "here is main\n\n";
return 0;
}
不過這個示例是有問題的,因為在建立了線程後線程開始執行,但是主線程main()并沒有停止腳步,仍然繼續執行然後退出,此時線程對象還是joinable的,線程仍然存在但指向它的線程對象已經銷毀,是以會抛出異常。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiNx8FesU2cfdGLwczX0xiRGZkRGZ0Xy9GbvNGLwIzXlpXazxSPFpWTx0keYpmSXVWQClGVF5UMR9Fd4VGdsATNfd3bkFGazxycykFaKdkYzZUbapXNXlleSdVY2pESa9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLykjN0YGN5YWYlNDO4kTNhRGZ0QDNkVzY4MTY0IWZ5IzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
那麼該如何保證子線程執行完了退出後再退出主線程呢?
2.thread::join()
使用join接口可以解決上述問題,join的作用是讓主線程等待直到該子線程執行結束,示例:
#include <iostream>
#include <thread>
using namespace std;
void t1()
{
for (int i = 0; i < 20; ++i)
{
cout << "t1111\n";
}
}
void t2()
{
for (int i = 0; i < 20; ++i)
{
cout << "t22222\n";
}
}
int main()
{
thread th1(t1);
thread th2(t2);
th1.join(); //等待th1執行完
th2.join(); //等待th2執行完
cout << "here is main\n\n";
return 0;
}
此時就可以正常地執行子線程了,同時注意最後一個輸出,說明了main是等待子線程結束才繼續執行的
需要注意的是線程對象執行了join後就不再joinable了,是以隻能調用join一次。
3.thread::detach()
(1.)中提到的問題,還可以使用detach來解決,detach是用來和線程對象分離的,這樣線程可以獨立地執行,不過這樣由于沒有thread對象指向該線程而失去了對它的控制,當對象析構時線程會繼續在背景執行,但是當主程式退出時并不能保證線程能執行完。如果沒有良好的控制機制或者這種背景線程比較重要,最好不用detach而應該使用join。
int main()
{
thread th1(t1);
thread th2(t2);
th1.detach();
th2.detach();
cout << "here is main\n\n";
return 0;
}
由結果可見線程并沒有執行完而退出:
4.mutex
頭檔案是,mutex是用來保證線程同步的,防止不同的線程同時操作同一個共享資料。
int cnt = 20;
mutex m;
void t1()
{
while (cnt > 0)
{
m.lock();
if (cnt > 0)
{
--cnt;
cout << cnt << endl;
}
m.unlock();
}
}
void t2()
{
while (cnt > 0)
{
m.lock();
if (cnt > 0)
{
--cnt;
cout << cnt << endl;
}
m.unlock();
}
}
int main()
{
thread th1(t1);
thread th2(t2);
th1.join();
th2.join();
return 0;
}
運作結果,cnt是依次遞減的,沒有因為多線程而打亂次序:
但是使用mutex是不安全的,當一個線程在解鎖之前異常退出了,那麼其它被阻塞的線程就無法繼續下去。
5.std::lock_guard
使用lock_guard則相對安全,它是基于作用域的,能夠自解鎖,當該對象建立時,它會像m.lock()一樣獲得互斥鎖,當生命周期結束時,它會自動析構(unlock),不會因為某個線程異常退出而影響其他線程。示例:
int cnt = 20;
mutex m;
void t1()
{
while (cnt > 0)
{
lock_guard<mutex> lockGuard(m);
if (cnt > 0)
{
--cnt;
cout << cnt << endl;
}
}
}
void t2()
{
while (cnt > 0)
{
lock_guard<mutex> lockGuard(m);
if (cnt > 0)
{
--cnt;
cout << cnt << endl;
}
}
}