[c++_thread] 對於thread中join,detach以及joinable講解


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;
}

最后輸出的結果
threadJoin
我們可以看到其中是一步步的執行,那么我們會不會有個疑惑這樣執行好像沒有用到進程,就是調用。那么這個時候我們可以使用get_id獲取線程的id,我們使用std::this_thread::get_id(),就可以獲取到相應的進程id,然后得到以下的輸出。
get_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
我們可以看到detach后,輸出是交叉進行的。

參考資料

http://www.cplusplus.com/reference/thread/thread/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM