文章目錄
簡 述: 上一篇講解了多線程的入門的知識,如何創建多線程程序,以及從虛擬地址空間和 PCB 分析線程的一些細節。本章再講述一些線程操作相關的函數:
- pthread_exit(): 退出一個線程,不會影響其他線程的
- pthread_jion(): 阻塞等待線程退出,獲取線程退出的狀態
- pthread_detach(): 設置線程分離的屬性
- pthread_cancel(): 殺死(取消)一個線程
- pthread_equal(): 判斷兩個線程是否相等,預留函數
編程環境:
💻: uos20
📎 gcc/g++ 8.3
📎 gdb8.0
💻: MacOS 10.14
📎 gcc/g++ 9.2
📎 gdb8.3
單個線程退出 pthread_exit():
- 作用: 一個進程的退出使用
exit(0)
; 而退出一個線程,使用pthread_exit(NULL)
;
void pthread_exit(void *value_ptr);
-
參數:
- value_ptr:必須指向全局,或者堆。是一個傳出參數,用來在該線程結束推出的時候,傳輸一個內容。若是指向局部變量,該線程被銷燬了的話,其他線程可能訪問不到此塊數據塊。
-
寫一個例子:
#include <stdio.h> #include <unistd.h> #include <pthread.h> int num = 13; //設置爲全局變量,在全局區域,共享 void* myfun(void* arg); int main(int argc, char *argv[]) { void* p = (void *)# //傳一個地址進去(voi* 也是 4 個字節) pthread_t id[5] = {0}; for (int i = 0; i < 5; i++) { pthread_create(&(id[i]), NULL, myfun, p); printf("i = %d, thread id: %ld\n", i, id[i]); } // pthread_exit(nullptr); //終止主線程 int j = 0; while (true) { sleep(1); printf ("main thread-----%d------\n", j++); } return 0; } void* myfun(void* arg) { for (int i = 0; i < 5; i++) { printf ("child thread-----%d------\n", i); if (i == 2) { _exit(0); //退出進程 // pthread_exit(nullptr); //終止主線程 } } return nullptr; }
-
運行結果:
阻塞等待退出線程退出 pthread_jion():
-
作用:
阻塞等待線程退出,獲取線程退出的狀態
int pthread_join(pthread_t thread, void **value_ptr);
-
參數:
- thread: 要回收的子線程的 id
- value_ptr:讀取線程退出時候的攜帶信息狀態;指向的內存和 pthread_exit 的參數是指向同一塊內存地址 。在上一個函數 pthread_exit(void *value_ptr) 中,線程退出的時候,傳出來了全局變量的指針; 而這裏第二個參數,此二級指針就可以讀出來這個值。
-
寫了一例子:
#include <stdio.h> #include <string.h> #include <unistd.h> #include <pthread.h> int number = 1234; //要是一個全局的變量哦,或者是堆的空間 void* myfun(void* arg); int main(int argc, char *argv[]) { pthread_t pthread = 0; int ret = pthread_create(&pthread, NULL, myfun, NULL); if (ret != 0) printf("error: %s\n", strerror(ret)); printf("parent thread id: %ld\n", pthread_self); void* ptr = nullptr; pthread_join(pthread, &ptr); //阻塞等待子線程退出,並且回收 pcb printf("number = %d\n", *((int*)ptr)); int i = 0; while (i < 10 ) { printf("parent i = %d\n", i++); } return 0; } void* myfun(void* arg) { printf("child thread id: %ld\n", pthread_self()); for (int i = 0; i < 5; i++) { if (i == 2) { // int number = 1234; //若是爲棧裏面的數據,則會組線程裏面,會崩潰或者失敗 pthread_exit(&number); //此處的地址,必須是指向堆或者全局變量 } printf("child i = %d\n", i); } return NULL; }
-
運行效果:
線程分離 pthread_detach():
在用 pthread_create 創建子線程的時候,第三個參數,是可以設置爲此屬性的;正常情況下,是由子線程死亡,是由父線程來釋放遺留的資源;但如果設置了此線程分離的屬性,那麼子線程是在創建的時候,就獨立於父線程,其死亡時候資源也是由自己來釋放。
int pthread_detach(pthread_t thread);
- 調用該函數之後,就不在需要調用 pthread_jion() 了
殺死(取消)線程 pthread_cancel():
int pthread_cancel(pthread_t thread);
- 注意:
- 要殺死子線程對應的處理的函數的內部,必須做一次系統調用。
- 系統調用函數有,eg: open,write, printf 等,這次都是最終會調用到系統層及的函數。
- 不涉及到系統層級調用,eg: int a = 10;
判斷線程是否相等 pthread_equal():
是一個預留函數 ,通過線程號 判斷兩個線程是否相等;目前不需要使用該函數。若是以後線程變爲返回一個結構體。就可以用此預留函數(修改一下實現)來判斷兩個線程是否實現了。
int pthread_equal(pthread_t t1, pthread_t t2);
下載地址:
歡迎 star 和 fork 這個系列的 linux 學習,附學習由淺入深的目錄。