2020/8/15
標簽(空格分隔):二零二零八月
今天主要是進行線程的學習
線程(std::thread)
我是直接從cpp官方文檔進行thread庫的學習。
看std::thread
的簡介時候,能夠知道
std::thread
的
Member types
- id //thread id
- native_handle_type //Native handle type
Member functions
- (constructor) //construct thread
- (destructor) //Thread destructor
- operator= //Move-assign thread
- get_id //Get thread id
- joinable //Check if joinable(可結合的)稍后解釋可結合的意思
- join //join thread
- detach //Detach thread
- swap //swap threads
- native_handle //Get native handle
- hardware concurrency[static] // detect hardware concurrency
non-member overloads
- swap(thread) // Swap threads(function)
因為類數據成員我們看注釋都可以讀懂相關的含義,所以直接上相關的成員函數
先是初始化
我們在初始化直接使用
std::thread name (function)
這樣的格式即可,如果我們不用后面的小括號的話,只進行線程的命名,那么就是進行了默認初始化
而在后面對的成員函數中,我先介紹Joinable,因為這個和其他成員函數更有連接性,介紹了joinable以后更好進行其他的成員函數的理解。
joinable
joinabe成員函數的作用在c++官方文檔中是返回線程是否是可結合的。
可結合的意思就是,一個線程是否能夠被執行Join或者是detch操作,因為相同的線程不能被join兩次,也不能join完再進行detach,同理也不可以被detach兩次,所以joinable函數就是判斷是否能進行可結合。
在c++的官方文檔中列出了不能被joinable的情況。
- 是被默認構造的(即沒有小括號的構造語句)std::thread name;
- 執行過move操作
- 執行過join或者detach
以下展示一個實例
#include <iostream> // std::cout
#include <thread> // std::thread
void mythread()
{
// do stuff...
}
int main()
{
std::thread foo;//這里就是上述提到的沒有小括號的構造語句,使用的是默認初始化
std::thread bar(mythread);
std::cout << "Joinable after construction:\n" << std::boolalpha;
std::cout << "foo: " << foo.joinable() << '\n';//這里會輸出false
std::cout << "bar: " << bar.joinable() << '\n';//這里輸出true
if (foo.joinable()) foo.join();//不會進行join操作
if (bar.joinable()) bar.join();//會進行join操作
std::cout << "Joinable after joining:\n" << std::boolalpha;
std::cout << "foo: " << foo.joinable() << '\n';//這里輸出false
std::cout << "bar: " << bar.joinable() << '\n';//這里也會輸出false,因為已經進行了一次join操作
return 0;
}
既然上面講提到了join以及detach,那么接下來自然就要進行join與detach的講解
join與detach
join在從c++官方文檔的介紹中,我們可以知道,join是用來進行同步的一個工具,當我們在主進程中使用join了一個子進程,那么我們主進程就要等待這個子進程運行完畢,並且回收子進程的資源后,再執行主進程的程序。
以下是測試代碼
#include<iostream>
#include<thread>
void thread_function() {
std::cout << "thread function excuting" << std::endl;
}
int main()
{
std::thread threadObj(thread_function);
threadObj.join();
std::cout << "I am Main function" << std::endl;
std::cout << "Exit of Main function" << std::endl;
system("pause");
return 0;
}
最后輸出的結果
我們可以看到其中是一步步的執行,那么我們會不會有個疑惑這樣執行好像沒有用到進程,就是調用。那么這個時候我們可以使用get_id
獲取線程的id,我們使用std::this_thread::get_id()
,就可以獲取到相應的進程id,然后得到以下的輸出。
我們可以看到進程的id是不一樣,說明我們是成功的控制了進程的運行。
而在我刪除掉了join試圖運行時,我發現它是按照不同順序來進行的,但是運行到最后會出現abort() has been called
,我去搜查了相關資料發現,join以后會表示這個線程可以destroy了,那么在子線程結束后會進行相關資源的回收,但是如何沒有join或者detach,就會導致不會產生標記,在最后整個進程結束時,該回收的資源沒有回收,就會產生錯誤。
那么detach呢,我們先從detach的字面意思進行理解下,detach指的是分離,脫離的意思,那么我們引申過來,在線程中的話,detach的意思就是將主線程和子線程進行分離,主線程是不會再等待子線程。
那么這個時候會有一個疑問,就是主線程結束的時候,進程也就結束,那么是不是表示子線程也是結束。結果不是,子線程的輸出只是不進行顯示,它還是會運行完,再被回收。
以下為detach代碼
#include<iostream>
#include<thread>
void thread_function() {
std::cout << "thread function excuting"<<"\n"<<std::this_thread::get_id() << std::endl;
std::cout << "thread function excuting1" << "\n" << std::endl;
std::cout << "thread function excuting2" << "\n" << std::endl;
}
int main()
{
std::thread threadObj(thread_function);
threadObj.detach();
std::cout << "I am Main function" << "\n"<<std::this_thread::get_id()<<std::endl;
std::cout << "I am Main function1" << "\n" << std::endl;
std::cout << "I am Main function2" << "\n" << std::endl;
std::cout << "I am Main function3" << "\n" << std::endl;
std::cout << "Exit of Main function" << std::endl;
return 0;
}
我們可以看到detach后,輸出是交叉進行的。