线程的控制(创建、等待、终止)、分离线程
一、線程控制
1、線程:線程是資源調(diào)度的基本單位,線程是進(jìn)程內(nèi)部的一個(gè)執(zhí)行流,在進(jìn)程的地址空間內(nèi)運(yùn)行。在Linux 下沒有真正意義上的線程,線程是用進(jìn)程模擬的,又被稱為輕量級(jí)進(jìn)程。
? ? ? ? 2、由于同?一進(jìn)程的多個(gè)線程共享同?一地址空間。因此Text Segment、Data Segment都是共享的,除此之外,各線程還共享以下進(jìn)程資源和環(huán)境:
1). ?文件描述符表;
2). 每種信號(hào)的處理?方式(SIG_IGN、SIG_DFL或者?自定義的信號(hào)處理函數(shù));
3). 當(dāng)前?工作?目錄;
4). ?用戶id和組id;
但有些資源是每個(gè)線程各有一份的:
1).線程id
2). 上下?文,包括各種寄存器的值、程序計(jì)數(shù)器和棧指針
3). 棧空間
4). errno變量
5). 信號(hào)屏蔽字
6). 調(diào)度優(yōu)先級(jí)
3、線程創(chuàng)建:
? ? ??函數(shù)原型:int pthread_create(pthread_t?thread, const pthread_attr_t *attr, void?(start_routine) (void?), void *arg);?
創(chuàng)建成功:返回0 ;創(chuàng)建失敗:返回錯(cuò)誤碼,可將錯(cuò)誤碼通過(guò)strerror()轉(zhuǎn)換為字符串描述。?
參數(shù)1:線程id地址(只在用戶區(qū)有效)。?
參數(shù)2:線程屬性,一般設(shè)置為NULL。?
參數(shù)3:函數(shù)指針,指向線程函數(shù)。?
參數(shù)4:線程函數(shù)的參數(shù)。
?? ? ?
創(chuàng)建結(jié)果:?
?? ? ? ? ? ? ? ??
????? 如果需要只終?止某個(gè)線程?而不終?止整個(gè)進(jìn)程,可以有三種?方法:
? ? ? ?1). 從線程函數(shù)return。這種?方法對(duì)主線程不適?用,從main函數(shù)return相當(dāng)于調(diào)?用exit。
? ? ? ?2). ?一個(gè)線程可以調(diào)?用pthread_cancel終?止同?一進(jìn)程中的另?一個(gè)線程,?用pthread_cancel終?止?一個(gè)線程分同步和異步兩種情況。
? ? ? ?3). 線程可以調(diào)?用pthread_exit終?止?自?己。
4、線程等待
? ? 返回值:成功返回0,失敗返回錯(cuò)誤號(hào)
? ? 調(diào)?用該函數(shù)的線程將掛起等待,直到id為thread的線程終?止。thread線程以不同的?方法終?止,通過(guò)pthread_join得到的終?止?fàn)顟B(tài)是不同的,總結(jié)如下:
? ? 1. 如果thread線程通過(guò)return返回,value_ptr所指向的單元?里存放的是thread線程函數(shù)的返回值。
? ? 2. 如果thread線程被別的線程調(diào)?用pthread_cancel異常終掉,value_ptr所指向的單元?里存放的是常數(shù)PTHREAD_CANCELED。
? ? 3. 如果thread線程是?自?己調(diào)?用pthread_exit終?止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數(shù)。 如果對(duì)thread線程的終?止?fàn)顟B(tài)不感興趣,可以 ? ? ?傳NULL給value_ptr參數(shù)
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void* thread1(void* arg)
{
? ? printf("new thread1\n");
? ? return (void*)123;
}
void* thread2(void* arg)
{
? ? while(1)
? ? {
? ? ? ? printf("new thread2\n");
? ? ? ? sleep(1);
? ? ? ? pthread_exit((void*)456);
? ? }
? ??
}
void* thread3(void* arg)//被其他線程cancel
{
? ? while(1)
? ? {
? ? ? ? printf("new thread3\n");
? ? ? ? sleep(1);
? ? }
? ? return NULL;
}
int main()
{
? ? pthread_t tid1,tid2,tid3,tid4;
? ? void* val = NULL;
? ? pthread_create(&tid1,NULL,thread1,NULL);
? ? pthread_create(&tid2,NULL,thread2,NULL);
? ? pthread_create(&tid3,NULL,thread3,NULL);
? ? pthread_create(&tid4,NULL,thread4,NULL);
? ??
? ? pthread_join(tid1,&val);
? ? printf("thread1 is quit,thread1 id is %lu, exit code:%d\n",tid1,(int)val);
? ? pthread_join(tid2,&val);
? ? printf("thread2 is quit,thread2 id is %lu, exit code:%d\n",tid2,(int)val);
? ? pthread_cancel(tid3);
? ? pthread_join(tid3,&val);
? ? printf("thread3 is quit,thread3 id is %lu, exit code:%d\n",tid3,(int)val);
? ? return 0;
}?
運(yùn)行結(jié)果:
注:
可見在Linux的pthread庫(kù)中常數(shù)PTHREAD_CANCELED的值是-1。可以在頭?文件pthread.h中找到它的定義。
一般情況下,線程終?止后,其終?止?fàn)顟B(tài)?一直保留到其它線程調(diào)?用pthread_join獲取它的狀態(tài)為止。 但是線程也可以被置為detach 狀態(tài),這樣的線程?一旦終止就?立刻回收它占?用的所有資源,?而不保留終?止?fàn)顟B(tài)。不能對(duì)?一個(gè)已經(jīng)處于detach狀態(tài)的線程調(diào)?用pthread_join,這樣的調(diào)?用將返回EINVAL。 對(duì)?一個(gè)尚未detach的線程調(diào)?用pthread_join或pthread_detach都可以把該線程置為detach狀態(tài),也 就是說(shuō),不能對(duì)同?一線程調(diào)?用兩次pthread_join,或者如果已經(jīng)對(duì)?一個(gè)線程調(diào)用 了pthread_detach就不能再調(diào)?用pthread_join了
二、分離線程
在任何?一個(gè)時(shí)間點(diǎn)上,線程是可結(jié)合的(joinable)或者是分離的(detached)。一個(gè)可結(jié)合的線程能夠被其他線程收回其資源和殺死。在被其他線程回收之前,
它的存儲(chǔ)器資源(例如棧)是不釋放的。相反,?一個(gè)分離的線程是不能被其他線程回收或殺死的,它的存儲(chǔ)器 資源在它終?止時(shí)由系統(tǒng)?自動(dòng)釋放。
1、默認(rèn)情況下,線程被創(chuàng)建成可結(jié)合的。為了避免存儲(chǔ)器泄漏,每個(gè)可結(jié)合線程都應(yīng)該要么被顯?示地回收,即調(diào)?用pthread_join;要么通過(guò)調(diào)?用pthread_detach
函數(shù)被分離。如果?一個(gè)可結(jié)合線程結(jié)束運(yùn)?行但沒有被join,則它的狀態(tài)類似于進(jìn)程中的Zombie Process,即還有?一部分資源沒有被回收,所以創(chuàng)建線程者應(yīng)該調(diào)用
pthread_join來(lái)等待線程運(yùn)?行結(jié)束,并可得到線程的退出代碼,回收其資源。
2、?由于調(diào)?用pthread_join后,如果該線程沒有運(yùn)?行結(jié)束,調(diào)?用者會(huì)被阻塞,在有些情況下我們并不希望如此。例如,在Web服務(wù)器中當(dāng)主線程為每個(gè)新來(lái)的連接
請(qǐng)求創(chuàng)建?一個(gè)?子線程進(jìn)?行處理的時(shí)候,主線程并不希望因?yàn)檎{(diào)?用pthread_join?而阻塞(因?yàn)檫€要繼續(xù)處理之后到來(lái)的連接請(qǐng)求),這時(shí)可以在?子線程中加入
代碼?pthread_detach(pthread_self());
或者?父線程調(diào)?用pthread_detach(thread_id)(?非阻塞,可?立即返回)
這將該?子線程的狀態(tài)設(shè)置為分離的(detached),如此一來(lái),該線程運(yùn)?行結(jié)束后會(huì)?自動(dòng)釋放所有資源。
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void* thread(void *_arg)
{
? ? //pthread_detach(pthread_self());//線程自已設(shè)置自已的可分離屬性
printf("new thread is run...\n");
? ? return (void*)1;
}
int main()
{
? ? pthread_t tid;
? ? int ret = pthread_create(&tid,NULL,thread,NULL);
? ? if(ret != 0)
? ? {
? ? ? ? printf("thread create failed,error code:%s\n",strerror(ret));
return ret;
? ? }
? ? sleep(1);
? ? pthread_detach(tid);//將子線程屬性設(shè)置為分離(非阻塞,可立即返回)
? ? void* val = NULL;
? ? if((pthread_join(tid, &val) != 0))
? ? {
? ? ? ? printf("thread wait failed\n");
ret = 1;
}
? ? else
? ? {
? ? ? ? printf("thread id : %u ,exit code : %d\n",tid, (int)val);
ret = 0;?
? ? }
? ? return ret;
}
運(yùn)行結(jié)果:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
總結(jié)
以上是生活随笔為你收集整理的线程的控制(创建、等待、终止)、分离线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【报告分享】 百度2021国潮骄傲搜索大
- 下一篇: 教你炒股票21:缠中说禅买卖点分析的完备