Linux線(xiàn)程之線(xiàn)程的創(chuàng)建、屬性、回收、退出、取消方式
1. 線(xiàn)程號(hào)
進(jìn)程號(hào)在系統(tǒng)中唯一,但線(xiàn)程號(hào)只在其所屬進(jìn)程環(huán)境中有效。
(1)pthread_self函數(shù)
#include<pthread.h>
pthread_t pthread_self(void);
/*
功能:
獲取線(xiàn)程號(hào)
返回值:
調(diào)用此函數(shù)線(xiàn)程的ID
*/pthread_self示例:
#include<stdio.h>
#include<pthread.h>
int main(int argc, const char* argv[]) {
pthread_t tid = 0;
tid = pthread_self();
printf("當(dāng)前線(xiàn)程id:%lu.\n", tid);
return 0;
}編譯時(shí)需要加上-pthread鏈接到pthread庫(kù)
運(yùn)行結(jié)果:

(2)pthread_equal函數(shù)
int pthraed_equal(pthread_t t1, pthread_t t2);
/*
功能:
判斷線(xiàn)程號(hào)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("線(xiàn)程id相等.\n");
} else {
printf("線(xiàn)程id不等.\n");
}
return 0;
}運(yùn)行結(jié)果:

2. 線(xiàn)程的創(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)建一個(gè)線(xiàn)程。
參數(shù):
thread:線(xiàn)程id地址,為傳出參數(shù);
attr:線(xiàn)程屬性結(jié)構(gòu)體,通常設(shè)置為NULL;
start_routine:線(xiàn)程函數(shù)入口地址
arg:傳給線(xiàn)程函數(shù)的參數(shù);
返回值:
成功:0
失?。悍?,未設(shè)置errno,不可使用perror。
*/pthread_create示例:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void* threadFunc(void* arg) { // 線(xiàn)程調(diào)度函數(shù)
int var = (int)(long)(arg);
printf("被創(chuàng)建線(xiàn)程id:%lu,傳過(guò)來(lái)的參數(shù):%d\n", pthread_self(), var);
return NULL;
}
int main(int argc, const char* argv[]) {
pthread_t tid;
int ret = -1;
// 初始化tid。因?yàn)椴皇撬邢到y(tǒng)中的pthread_t都是unsigned int, 因此最好使用memset初始化。
memset(&tid, 0, sizeof(tid));
// 創(chuàng)建線(xiàn)程
ret = pthread_create(&tid, NULL, threadFunc, (void*)0x3);
if (0 != ret) {
printf("線(xiàn)程創(chuàng)建失??!\n");
return 1;
}
printf("按下任意鍵繼續(xù)...\n");
getchar();
printf("主線(xiàn)程id:%lu\n", pthread_self());
return 0;
}運(yùn)行結(jié)果:

3. 線(xiàn)程屬性
typedef struct {
int etachstate; // 線(xiàn)程的分離狀態(tài)
int schedpolicy; // 線(xiàn)程的調(diào)度策略
struct sched_param schedparam; // 線(xiàn)程的調(diào)度參數(shù)
int inheritsched; // 線(xiàn)程的繼承性
int scope; // 線(xiàn)程的作用域
size_t guardsize; // 線(xiàn)程棧末尾的警戒緩沖區(qū)大小
int stackaddr_set; // 線(xiàn)程棧的設(shè)置
void* stackaddr; // 線(xiàn)程棧的位置
size_t stacksize; // 線(xiàn)程棧的大小
} pthread_attr_t;
/*
功能:
線(xiàn)程屬性結(jié)構(gòu)體;
主要成員:
etachstate:線(xiàn)程的分離狀態(tài)
guardsize:線(xiàn)程棧末尾的警戒緩沖區(qū)大小
stackaddr:線(xiàn)程棧的位置
stacksize:線(xiàn)程棧的大小
注意:
線(xiàn)程屬性值不能直接設(shè)置,需使用相關(guān)函數(shù)進(jìn)行操作。
如pthread_create之前用pthread_attr_init初始化,
之后用pthread_attr_destory釋放資源。
*/(1)線(xiàn)程屬性的初始化和銷(xiāo)毀
#include<pthread.h>
int pthread_attr_init(pthread_attr_t* attr);
/*
功能:
初始化線(xiàn)程屬性attr。
參數(shù):
attr:待初始化的線(xiàn)程屬性結(jié)構(gòu)體。
返回值:
成功:0
失?。哄e(cuò)誤碼
*/
int pthread_attr_destory(pthread_attr_t* attr);/*
功能:
銷(xiāo)毀線(xiàn)程屬性attr。
參數(shù):
attr:線(xiàn)程屬性結(jié)構(gòu)體。
返回值:
成功:0
失?。悍?錯(cuò)誤碼
*/(2)線(xiàn)程分離狀態(tài)屬性設(shè)置
- 線(xiàn)程分離狀態(tài):無(wú)需其他線(xiàn)程阻塞等待線(xiàn)程結(jié)束以回收已結(jié)束線(xiàn)程的資源,而是讓內(nèi)核回收已結(jié)束線(xiàn)程的資源。
- 線(xiàn)程非分離狀態(tài):某個(gè)線(xiàn)程(如主線(xiàn)程)阻塞等待子線(xiàn)程結(jié)束以回收其資源。
#include<pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t* attr, int detachstate);
/*
功能:
設(shè)置線(xiàn)程屬性為分離。
參數(shù):
attr:已初始化的線(xiàn)程屬性結(jié)構(gòu)體;
detachstate:是否分離:
PTHREAD_CREATE_DETACHED:分離
PTHREAD_CREATE_JOINABLE:非分離
返回值:
成功:0
失?。悍?
*/
int pthread_attr_getdetachstate(const pthread_attr_t* attr, int* detachstate);
/*
功能:
獲取線(xiàn)程是否分離狀態(tài)
參數(shù):
attr:線(xiàn)程屬性結(jié)構(gòu)體。
detachstate:是否分離:
PTHREAD_CREATE_DETACHED:分離
PTHREAD_CREATE_JOINABLE:非分離
返回值:
成功:0
失?。悍?錯(cuò)誤碼
*/線(xiàn)程設(shè)置分離屬性示例
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
void* func(void* arg) {
printf("子線(xiàn)程開(kāi)始...\n");
sleep(2);
printf("子線(xiàn)程結(jié)束...\n");
pthread_exit(NULL);
}
int main(int argc, const char* argv[]) {
int ret = -1;
pthread_t tid = -1;
pthread_attr_t attr;
// 初始化線(xiàn)程屬性
ret = pthread_attr_init(&attr);
if (0 != ret) {
printf("線(xiàn)程屬性初始化失敗。\n");
return 1;
}
// 設(shè)置線(xiàn)程屬性為分離狀態(tài)
ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (0 != ret) {
printf("線(xiàn)程分離屬性設(shè)置失敗。\n");
return 1;
}
// 創(chuàng)建線(xiàn)程
ret = pthread_create(&tid, &attr, func, NULL);
if (0 != ret) {
printf("線(xiàn)程創(chuàng)建失敗.\n");
return 1;
}
sleep(3);
// join看看是否為分離狀態(tài)
ret = pthread_join(tid, NULL);
if (0 != ret) {
printf("線(xiàn)程為分離狀態(tài),無(wú)需join.\n");
} else {
printf("線(xiàn)程為非分離狀態(tài),已被join.\n");
}
// 銷(xiāo)毀線(xiàn)程屬性
ret = pthread_attr_destroy(&attr);
if (0 != ret) {
printf("線(xiàn)程屬性銷(xiāo)毀失敗。\n");
return 1;
}
return 0;
}運(yùn)行結(jié)果:

(3)線(xiàn)程棧大小獲取和設(shè)置
#include<pthread.h>
int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize);
/*
功能:
設(shè)置線(xiàn)程棧大小。
參數(shù):
attr:線(xiàn)程屬性結(jié)構(gòu)體;
stacksize:線(xiàn)程棧大?。?
返回值:
成功:0;
失敗:錯(cuò)誤碼
*/
int pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* stacksize);
/*
功能:
獲取線(xiàn)程棧大小。
參數(shù):
attr:線(xiàn)程屬性結(jié)構(gòu)體指針;
stacksize:返回的線(xiàn)程棧大??;
返回值:
成功:0;
失?。悍?錯(cuò)誤碼
*/4. 線(xiàn)程的回收
(1)pthread_join函數(shù)
主線(xiàn)程回收線(xiàn)程資源,會(huì)阻塞。
#include<pthread.h>
int pthread_join(pthread_t thread, void** retval);
/*
功能:
類(lèi)似于wait()函數(shù)。等待線(xiàn)程thread結(jié)束,回收線(xiàn)程資源;若線(xiàn)程已結(jié)束,則會(huì)立即返回。
參數(shù):
thread:等待回收的線(xiàn)程號(hào);
retval:存儲(chǔ)進(jìn)程退出狀態(tài)的指針的地址;
返回值:
成功:0
失敗:非0錯(cuò)誤碼
*/pthread_join示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<unistd.h>
void* func() {
printf("子線(xiàn)程開(kāi)始執(zhí)行...\n");
sleep(3);
printf("子線(xiàn)程結(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)建線(xiàn)程
ret = pthread_create(&tid, NULL, func, NULL);
if (0 != ret) {
printf("線(xiàn)程創(chuàng)建失敗.\n");
return 1;
}
printf("主線(xiàn)程執(zhí)行...\n");
// 等待線(xiàn)程結(jié)束 pthread_join會(huì)阻塞
ret = pthread_join(tid, &retp);
if (0 != ret) {
printf("線(xiàn)程join失敗.\n");
return 1;
}
printf("retp: %p\n", retp);
printf("主線(xiàn)程退出...\n");
return 0;
}運(yùn)行結(jié)果:

(2)pthread_detach函數(shù)
內(nèi)核回收線(xiàn)程資源,不會(huì)阻塞。
#include<pthread.h>
int pthread_detach(pthread_t thread);
/*
功能:
使線(xiàn)程thread與當(dāng)前進(jìn)程分離,之后線(xiàn)程結(jié)束后的資源回收由內(nèi)核完成,因此不會(huì)阻塞。
參數(shù):
thread:線(xiàn)程號(hào);
返回值:
成功:0
失?。悍?
*/pthread_detach示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
void* func(void* arg) {
printf("子線(xiàn)程開(kāi)始...\n");
for (int i = 0; i < 3;++i) {
sleep(1);
printf("子線(xiàn)程工作%ds\n", i);
}
printf("子線(xiàn)程結(jié)束...\n");
return NULL;
}
int main(int argc, const char* argv[]) {
int ret = -1;
pthread_t tid = -1;
// 創(chuàng)建線(xiàn)程
ret = pthread_create(&tid, NULL, func, NULL);
if (0 != ret) {
printf("線(xiàn)程創(chuàng)建失敗.\n");
return 1;
}
// 設(shè)置線(xiàn)程分離
ret = pthread_detach(tid);
if (0 != ret) {
printf("線(xiàn)程分離失敗.\n");
return 1;
}
printf("主線(xiàn)程:按回車(chē)鍵退出..\n");
getchar();
return 0;
}運(yùn)行結(jié)果:
線(xiàn)程設(shè)置為detach狀態(tài),主線(xiàn)程不必阻塞等待回收子線(xiàn)程資源,而是由內(nèi)核完成。

5. 線(xiàn)程的退出
若在線(xiàn)程中用exit函數(shù)退出,則導(dǎo)致整個(gè)進(jìn)程退出,而非退出這一個(gè)線(xiàn)程。
如下三者可在不結(jié)束整個(gè)進(jìn)程的情況下結(jié)束線(xiàn)程:
a)線(xiàn)程從執(zhí)行函數(shù)中返回;
b)線(xiàn)程調(diào)用pthread_exit退出線(xiàn)程;
c)線(xiàn)程被同一進(jìn)程中的其它線(xiàn)程取消。
pthread_exit函數(shù)
#include<pthread.h>
void pthread_exit(void* retval);
/*
功能:
退出調(diào)用線(xiàn)程。
參數(shù):
retval:存儲(chǔ)線(xiàn)程退出狀態(tài)的指針。
*/6. 線(xiàn)程的取消
pthread_cancel函數(shù)
#include<pthread.h>
int pthread_cancel(pthread_t thread);
/*
功能:
殺死線(xiàn)程thread;
參數(shù):
thread:目標(biāo)線(xiàn)程ID;
返回值:
成功:0
失?。悍?錯(cuò)誤碼。
*/pthread_cancel示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
void* func(void* arg) {
printf("子線(xiàn)程開(kāi)始...\n");
for (int i = 0; i < 5;++i) {
sleep(1);
printf("子線(xiàn)程工作%ds\n", i);
}
printf("子線(xiàn)程結(jié)束...\n");
pthread_exit(NULL);
}
int main(int argc, const char* argv[]) {
int ret = -1;
pthread_t tid = -1;
// 創(chuàng)建線(xiàn)程
ret = pthread_create(&tid, NULL, func, NULL);
if (0 != ret) {
printf("線(xiàn)程創(chuàng)建失敗.\n");
return 1;
}
// 設(shè)置線(xiàn)程分離
ret = pthread_detach(tid);
if (0 != ret) {
printf("線(xiàn)程分離失敗.\n");
return 1;
}
sleep(3);
pthread_cancel(tid); // 殺死線(xiàn)程
printf("主線(xiàn)程:按回車(chē)鍵退出..\n");
getchar();
return 0;
}運(yùn)行結(jié)果:

7. 線(xiàn)程使用注意事項(xiàng)
(1)主線(xiàn)程退出,而其余線(xiàn)程不退出,主線(xiàn)程應(yīng)調(diào)用pthread_exit;
(2)避免僵尸線(xiàn)程方式:
- a)pthread_join;
- b)pthread_detach;
- c)pthread_create前設(shè)置線(xiàn)程分離屬性;
(3)malloc和mmap申請(qǐng)的內(nèi)存可被其他線(xiàn)程釋放;
(4)避免在多線(xiàn)程中fork,除非馬上使用exec;
(5)避免多線(xiàn)程中使用信號(hào)機(jī)制。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
CentOS下使用Squid架設(shè)CDN服務(wù)器的方法
這篇文章主要介紹了CentOS下使用Squid架設(shè)CDN服務(wù)器的方法,需要的朋友可以參考下2014-07-07
linux禁止ping的實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了linux禁止ping的實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05
一條命令讓你明白shell中read命令的常用參數(shù)
今天小編就為大家分享一篇關(guān)于一條命令讓你明白shell中read命令的常用參數(shù),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
linux允許端口遠(yuǎn)程訪(fǎng)問(wèn)開(kāi)放端口的方法
今天小編就為大家分享一篇linux允許端口遠(yuǎn)程訪(fǎng)問(wèn)開(kāi)放端口的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07
詳解如何在Linux中重置MySQL或者M(jìn)ariaDB的root密碼
本篇文章主要介紹了如何在 Linux 中重置 MySQL 或者 MariaDB 的 root 密碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03
Ubuntu系統(tǒng)端口查詢(xún)與管理的詳細(xì)分析
事情起因是寶塔的CPU負(fù)載過(guò)大,重啟服務(wù)進(jìn)程之后還是爆,后續(xù)發(fā)現(xiàn)是端口被占用,導(dǎo)致服務(wù)重啟不起來(lái),所以本文給大家介紹了Ubuntu系統(tǒng)端口查詢(xún)與管理的詳細(xì)分析,需要的朋友可以參考下2024-11-11

