Linux線程之線程的創(chuàng)建、屬性、回收、退出、取消方式
1. 線程號
進程號在系統(tǒng)中唯一,但線程號只在其所屬進程環(huán)境中有效。
(1)pthread_self函數(shù)
#include<pthread.h> pthread_t pthread_self(void); /* 功能: 獲取線程號 返回值: 調(diào)用此函數(shù)線程的ID */
pthread_self示例:
#include<stdio.h> #include<pthread.h> int main(int argc, const char* argv[]) { pthread_t tid = 0; tid = pthread_self(); printf("當前線程id:%lu.\n", tid); return 0; }
編譯時需要加上-pthread鏈接到pthread庫
運行結(jié)果:
(2)pthread_equal函數(shù)
int pthraed_equal(pthread_t t1, pthread_t t2); /* 功能: 判斷線程號t1、t2是否相等。 返回值: 相等:非0 不等:0 */
pthread_equal示例:
#include<stdio.h> #include<pthread.h> int main(int argc, const char* argv[]) { pthread_t tid = 0; tid = pthread_self(); if (pthread_equal(tid, pthread_self())) { printf("線程id相等.\n"); } else { printf("線程id不等.\n"); } return 0; }
運行結(jié)果:
2. 線程的創(chuàng)建
pthread_create函數(shù)
#include<pthread.h> int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_coutine)(void*), void* arg); /* 功能: 創(chuàng)建一個線程。 參數(shù): thread:線程id地址,為傳出參數(shù); attr:線程屬性結(jié)構(gòu)體,通常設(shè)置為NULL; start_routine:線程函數(shù)入口地址 arg:傳給線程函數(shù)的參數(shù); 返回值: 成功:0 失?。悍?,未設(shè)置errno,不可使用perror。 */
pthread_create示例:
#include<stdio.h> #include<pthread.h> #include<unistd.h> void* threadFunc(void* arg) { // 線程調(diào)度函數(shù) int var = (int)(long)(arg); printf("被創(chuàng)建線程id:%lu,傳過來的參數(shù):%d\n", pthread_self(), var); return NULL; } int main(int argc, const char* argv[]) { pthread_t tid; int ret = -1; // 初始化tid。因為不是所有系統(tǒng)中的pthread_t都是unsigned int, 因此最好使用memset初始化。 memset(&tid, 0, sizeof(tid)); // 創(chuàng)建線程 ret = pthread_create(&tid, NULL, threadFunc, (void*)0x3); if (0 != ret) { printf("線程創(chuàng)建失??!\n"); return 1; } printf("按下任意鍵繼續(xù)...\n"); getchar(); printf("主線程id:%lu\n", pthread_self()); return 0; }
運行結(jié)果:
3. 線程屬性
typedef struct { int etachstate; // 線程的分離狀態(tài) int schedpolicy; // 線程的調(diào)度策略 struct sched_param schedparam; // 線程的調(diào)度參數(shù) int inheritsched; // 線程的繼承性 int scope; // 線程的作用域 size_t guardsize; // 線程棧末尾的警戒緩沖區(qū)大小 int stackaddr_set; // 線程棧的設(shè)置 void* stackaddr; // 線程棧的位置 size_t stacksize; // 線程棧的大小 } pthread_attr_t; /* 功能: 線程屬性結(jié)構(gòu)體; 主要成員: etachstate:線程的分離狀態(tài) guardsize:線程棧末尾的警戒緩沖區(qū)大小 stackaddr:線程棧的位置 stacksize:線程棧的大小 注意: 線程屬性值不能直接設(shè)置,需使用相關(guān)函數(shù)進行操作。 如pthread_create之前用pthread_attr_init初始化, 之后用pthread_attr_destory釋放資源。 */
(1)線程屬性的初始化和銷毀
#include<pthread.h> int pthread_attr_init(pthread_attr_t* attr); /* 功能: 初始化線程屬性attr。 參數(shù): attr:待初始化的線程屬性結(jié)構(gòu)體。 返回值: 成功:0 失?。哄e誤碼 */ int pthread_attr_destory(pthread_attr_t* attr);/* 功能: 銷毀線程屬性attr。 參數(shù): attr:線程屬性結(jié)構(gòu)體。 返回值: 成功:0 失敗:非0錯誤碼 */
(2)線程分離狀態(tài)屬性設(shè)置
- 線程分離狀態(tài):無需其他線程阻塞等待線程結(jié)束以回收已結(jié)束線程的資源,而是讓內(nèi)核回收已結(jié)束線程的資源。
- 線程非分離狀態(tài):某個線程(如主線程)阻塞等待子線程結(jié)束以回收其資源。
#include<pthread.h> int pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate); /* 功能: 設(shè)置線程屬性為分離。 參數(shù): attr:已初始化的線程屬性結(jié)構(gòu)體; detachstate:是否分離: PTHREAD_CREATE_DETACHED:分離 PTHREAD_CREATE_JOINABLE:非分離 返回值: 成功:0 失?。悍? */ int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate); /* 功能: 獲取線程是否分離狀態(tài) 參數(shù): attr:線程屬性結(jié)構(gòu)體。 detachstate:是否分離: PTHREAD_CREATE_DETACHED:分離 PTHREAD_CREATE_JOINABLE:非分離 返回值: 成功:0 失?。悍?錯誤碼 */
線程設(shè)置分離屬性示例
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<pthread.h> void* func(void* arg) { printf("子線程開始...\n"); sleep(2); printf("子線程結(jié)束...\n"); pthread_exit(NULL); } int main(int argc, const char* argv[]) { int ret = -1; pthread_t tid = -1; pthread_attr_t attr; // 初始化線程屬性 ret = pthread_attr_init(&attr); if (0 != ret) { printf("線程屬性初始化失敗。\n"); return 1; } // 設(shè)置線程屬性為分離狀態(tài) ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (0 != ret) { printf("線程分離屬性設(shè)置失敗。\n"); return 1; } // 創(chuàng)建線程 ret = pthread_create(&tid, &attr, func, NULL); if (0 != ret) { printf("線程創(chuàng)建失敗.\n"); return 1; } sleep(3); // join看看是否為分離狀態(tài) ret = pthread_join(tid, NULL); if (0 != ret) { printf("線程為分離狀態(tài),無需join.\n"); } else { printf("線程為非分離狀態(tài),已被join.\n"); } // 銷毀線程屬性 ret = pthread_attr_destroy(&attr); if (0 != ret) { printf("線程屬性銷毀失敗。\n"); return 1; } return 0; }
運行結(jié)果:
(3)線程棧大小獲取和設(shè)置
#include<pthread.h> int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize); /* 功能: 設(shè)置線程棧大小。 參數(shù): attr:線程屬性結(jié)構(gòu)體; stacksize:線程棧大??; 返回值: 成功:0; 失敗:錯誤碼 */ int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stacksize); /* 功能: 獲取線程棧大小。 參數(shù): attr:線程屬性結(jié)構(gòu)體指針; stacksize:返回的線程棧大??; 返回值: 成功:0; 失?。悍?錯誤碼 */
4. 線程的回收
(1)pthread_join函數(shù)
主線程回收線程資源,會阻塞。
#include<pthread.h> int pthread_join(pthread_t thread, void** retval); /* 功能: 類似于wait()函數(shù)。等待線程thread結(jié)束,回收線程資源;若線程已結(jié)束,則會立即返回。 參數(shù): thread:等待回收的線程號; retval:存儲進程退出狀態(tài)的指針的地址; 返回值: 成功:0 失?。悍?錯誤碼 */
pthread_join示例:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<pthread.h> #include<unistd.h> void* func() { printf("子線程開始執(zhí)行...\n"); sleep(3); printf("子線程結(jié)束執(zhí)行...\n"); return (void*)0x3; } int main(int argc, const char* argv[]) { pthread_t tid; int ret = -1; void* retp = NULL; memset(&tid, 0, sizeof(tid)); // 創(chuàng)建線程 ret = pthread_create(&tid, NULL, func, NULL); if (0 != ret) { printf("線程創(chuàng)建失敗.\n"); return 1; } printf("主線程執(zhí)行...\n"); // 等待線程結(jié)束 pthread_join會阻塞 ret = pthread_join(tid, &retp); if (0 != ret) { printf("線程join失敗.\n"); return 1; } printf("retp: %p\n", retp); printf("主線程退出...\n"); return 0; }
運行結(jié)果:
(2)pthread_detach函數(shù)
內(nèi)核回收線程資源,不會阻塞。
#include<pthread.h> int pthread_detach(pthread_t thread); /* 功能: 使線程thread與當前進程分離,之后線程結(jié)束后的資源回收由內(nèi)核完成,因此不會阻塞。 參數(shù): thread:線程號; 返回值: 成功:0 失?。悍? */
pthread_detach示例:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<pthread.h> void* func(void* arg) { printf("子線程開始...\n"); for (int i = 0; i < 3;++i) { sleep(1); printf("子線程工作%ds\n", i); } printf("子線程結(jié)束...\n"); return NULL; } int main(int argc, const char* argv[]) { int ret = -1; pthread_t tid = -1; // 創(chuàng)建線程 ret = pthread_create(&tid, NULL, func, NULL); if (0 != ret) { printf("線程創(chuàng)建失敗.\n"); return 1; } // 設(shè)置線程分離 ret = pthread_detach(tid); if (0 != ret) { printf("線程分離失敗.\n"); return 1; } printf("主線程:按回車鍵退出..\n"); getchar(); return 0; }
運行結(jié)果:
線程設(shè)置為detach狀態(tài),主線程不必阻塞等待回收子線程資源,而是由內(nèi)核完成。
5. 線程的退出
若在線程中用exit函數(shù)退出,則導致整個進程退出,而非退出這一個線程。
如下三者可在不結(jié)束整個進程的情況下結(jié)束線程:
a)線程從執(zhí)行函數(shù)中返回;
b)線程調(diào)用pthread_exit退出線程;
c)線程被同一進程中的其它線程取消。
pthread_exit函數(shù)
#include<pthread.h> void pthread_exit(void* retval); /* 功能: 退出調(diào)用線程。 參數(shù): retval:存儲線程退出狀態(tài)的指針。 */
6. 線程的取消
pthread_cancel函數(shù)
#include<pthread.h> int pthread_cancel(pthread_t thread); /* 功能: 殺死線程thread; 參數(shù): thread:目標線程ID; 返回值: 成功:0 失?。悍?錯誤碼。 */
pthread_cancel示例:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<pthread.h> void* func(void* arg) { printf("子線程開始...\n"); for (int i = 0; i < 5;++i) { sleep(1); printf("子線程工作%ds\n", i); } printf("子線程結(jié)束...\n"); pthread_exit(NULL); } int main(int argc, const char* argv[]) { int ret = -1; pthread_t tid = -1; // 創(chuàng)建線程 ret = pthread_create(&tid, NULL, func, NULL); if (0 != ret) { printf("線程創(chuàng)建失敗.\n"); return 1; } // 設(shè)置線程分離 ret = pthread_detach(tid); if (0 != ret) { printf("線程分離失敗.\n"); return 1; } sleep(3); pthread_cancel(tid); // 殺死線程 printf("主線程:按回車鍵退出..\n"); getchar(); return 0; }
運行結(jié)果:
7. 線程使用注意事項
(1)主線程退出,而其余線程不退出,主線程應(yīng)調(diào)用pthread_exit;
(2)避免僵尸線程方式:
- a)pthread_join;
- b)pthread_detach;
- c)pthread_create前設(shè)置線程分離屬性;
(3)malloc和mmap申請的內(nèi)存可被其他線程釋放;
(4)避免在多線程中fork,除非馬上使用exec;
(5)避免多線程中使用信號機制。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Linux、ubuntu系統(tǒng)下查看顯卡型號、顯卡信息詳解
這篇文章主要介紹了如何在Linux、ubuntu系統(tǒng)下查看顯卡型號、顯卡信息的方法,需要的朋友可以參考下2022-04-04阿里云ECS(linux)一鍵安裝web環(huán)境sh安裝步驟
這篇文章主要介紹了阿里云ECS(linux)一鍵安裝web環(huán)境sh安裝步驟,需要的朋友可以參考下2016-10-10centos 7中設(shè)置tomcat 7為系統(tǒng)服務(wù)的方法詳解
這篇文章主要給大家介紹了關(guān)于在centos 7中設(shè)置tomcat 7為系統(tǒng)服務(wù)的相關(guān)資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來跟著小編一起學習學習吧。2017-06-06VMware虛擬機安裝Centos操作系統(tǒng)的教程
這篇文章主要為大家詳細介紹了VMware虛擬機安裝Centos操作系統(tǒng)的教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07