日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

linux用户空间和内核exit的语义--linux没有线程

發(fā)布時(shí)間:2023/11/29 linux 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux用户空间和内核exit的语义--linux没有线程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如果你在程序中調(diào)用了exit,那么很顯然你的程序會(huì)退出,可是至于為何會(huì)退出那就是庫(kù)的事情了,我為什么說(shuō)只是庫(kù)的事情而不關(guān)linux內(nèi)核的事情呢?那是因?yàn)閘inux內(nèi)核根本不管用戶(hù)空間的行為策略。庫(kù)的策略是什么?很簡(jiǎn)單的退出當(dāng)前進(jìn)程嗎?如果是多線程的程序呢?多線程的程序它的行為又是什么呢?在我們探究庫(kù)的行為以及探究庫(kù)為何會(huì)有這樣的行為之前首先談?wù)剝?nèi)核對(duì)exit的實(shí)現(xiàn)sys_exit,在sys_exit中,我絲毫找不到關(guān)于退出線程的代碼,按照常規(guī)的思考,如果sys_exit負(fù)責(zé)將本進(jìn)程的所有線程都退出的話(huà),那么合理的辦法就是在本進(jìn)程的signal結(jié)構(gòu)體上append上一個(gè)SIGKILL信號(hào),然后喚醒所有的線程的task_struct,因?yàn)橐粋€(gè)進(jìn)程的所有線程共享信號(hào)處理結(jié)構(gòu),因此每個(gè)被喚醒的線程的task_struct都會(huì)在信號(hào)處理時(shí)自己退出,這樣看起來(lái)很不錯(cuò),也很合理,如果是windows想到了這個(gè)主意,那么它肯定會(huì)采用的,可是這是linux。

linux中沒(méi)有線程的概念,我這么說(shuō)不是在說(shuō)linux很落后嗎?現(xiàn)代操作系統(tǒng)中都會(huì)有線程的實(shí)現(xiàn)。其實(shí)不然,在linux中,線程并不是一個(gè)操作系統(tǒng)的內(nèi)秉性概念,在linux中只有進(jìn)程,然后可以在進(jìn)程的基礎(chǔ)上輕松實(shí)現(xiàn)線程,這個(gè)意義上,線程僅僅是一個(gè)策略,一個(gè)由很多的實(shí)體概念組合而成的概念。其實(shí)在linux上,完全不能用傳統(tǒng)的操作系統(tǒng)的標(biāo)準(zhǔn)來(lái)說(shuō)明,比如線程,進(jìn)程,然后又分了什么X程,這樣豈不是越來(lái)越亂,每引入一個(gè)概念,操作系統(tǒng)的體系就要大動(dòng)一番,在linux中就有一個(gè)執(zhí)行緒的概念,該執(zhí)行緒就是task_struct,你把它理解成進(jìn)程也好,理解成線程也罷,其實(shí)它可以表達(dá)成任何可以執(zhí)行的東西,在task_struct的基礎(chǔ)上,我們可以壘砌很多外延的東西,比如進(jìn)程,線程等等,在linux中,只有task_struct一個(gè)概念,進(jìn)程,線程只是它的外延而已,task_struct和不同的特性組合就可以表示程不同的外延,比如,它和gid,uid等組合就是進(jìn)程,它和線程組或者TGID組合就是線程。

理解了一行原則,exit的內(nèi)核行為就十分簡(jiǎn)單了,既然內(nèi)核原始的只有task_struct這一個(gè)執(zhí)行緒概念,那么它就是應(yīng)該有它的創(chuàng)建和銷(xiāo)毀的內(nèi)核api,并且在哲學(xué)意義上這兩個(gè)內(nèi)核api是對(duì)稱(chēng)的,我們很多人都了解linux的線程創(chuàng)建,其實(shí)也是用的fork,cone在內(nèi)核不也是用fork實(shí)現(xiàn)的嗎?創(chuàng)建一個(gè)現(xiàn)代操作系統(tǒng)的線程在linux中就是創(chuàng)建一個(gè)執(zhí)行緒,也就是創(chuàng)建一個(gè)task_struct,那么do_fork就是干這個(gè)的,相反的,對(duì)于退出并沒(méi)有多少人去關(guān)注,既然fork創(chuàng)建了一個(gè)task_struct,那么exit就是銷(xiāo)毀一個(gè)task_struct,別的并不做什么,fork沒(méi)有線程的概念,它只負(fù)責(zé)按照用戶(hù)提供的參數(shù)創(chuàng)建一個(gè)task_struct,這里線程這個(gè)外延是通過(guò)參數(shù)體現(xiàn)的,既然參數(shù)可以賦予一個(gè)task_struct以線程的含義,那么fork中也就根據(jù)此含義對(duì)task_struct的字段進(jìn)行了設(shè)置,以表示這是一個(gè)線程,在linux內(nèi)核中并沒(méi)有線程的概念,而僅有線程的外延,既然創(chuàng)建行為fork如此,那么銷(xiāo)毀行為exit也是如此,如此一來(lái)就可以理解exit中根本就不可能有什么向本進(jìn)程的所有線程發(fā)送退出信號(hào)一說(shuō),它只管銷(xiāo)毀這個(gè)調(diào)用exit的執(zhí)行緒的task_struct(其實(shí)是遞減這個(gè)task_stuct的引用計(jì)數(shù)),而不管什么線程的概念,那么誰(shuí)會(huì)去管線程的概念呢?當(dāng)然是誰(shuí)定義誰(shuí)管了,比如Posix或者用戶(hù)的其它庫(kù),內(nèi)核將線程這個(gè)task_struct的外延導(dǎo)出給用戶(hù),那么用戶(hù)就可以用這個(gè)外延的一系列特性以及行為準(zhǔn)則來(lái)操作這個(gè)線程外延,故而用戶(hù)庫(kù)可以用內(nèi)核提供的最小化的正交組合接口配上線程這個(gè)外延來(lái)組合成一個(gè)可以退出所有線程的接口,其實(shí)就是對(duì)于每一個(gè)線程調(diào)用其exit。

內(nèi)核實(shí)現(xiàn)畢竟是內(nèi)核實(shí)現(xiàn),linux還是遵循posix的,因此它提供了一個(gè)系統(tǒng)調(diào)用sys_exit_group,之所以如此是因?yàn)檫@樣的話(huà),用戶(hù)庫(kù)就不必再費(fèi)勁心機(jī)切入每個(gè)線程并且在每個(gè)線程調(diào)用exit了,當(dāng)然這也不是linux內(nèi)核所希望的。sys_exit_group中會(huì)調(diào)用zap_other_threads(current)來(lái)退出每個(gè)線程,不管怎樣,exit_group的提供僅僅是為了遵循posix,而exit才是linux的設(shè)計(jì)中原汁原味的執(zhí)行緒操作系統(tǒng)調(diào)用,其實(shí)在用戶(hù)庫(kù)里面完全可以用向所有的線程發(fā)送SIGKILL信號(hào)來(lái)實(shí)現(xiàn)exit。

舉個(gè)例子來(lái)說(shuō)明一切:

#include.h>

#include

#include.h>

#include

void direct_exit() //這個(gè)函數(shù)直接用系統(tǒng)調(diào)用實(shí)現(xiàn)了exit,即到了內(nèi)核直接調(diào)用sys_exit

{

int a = 1,b = 0;

asm("movl %0,%%eax/n/t" /

"movl %1,%%ebx/n/t" /

"int $0x80/n/t" /

::"r" (a),"r" (b));

}

int handler( void *p)

{

while(1)

{

sleep(1);

printf("Sub thread is running/n");

}

}

int main(int argc, char* argv[])

{

int i = 0;

clone(handler, &i-1024, CLONE_SIGHAND|CLONE_VM|CLONE_THREAD, NULL);

while(1)

{

sleep(1);

printf("Main thread is running/n");

if(i++>15)

{

direct_exit();//直接退出,和線程沒(méi)有關(guān)系,子線程handler繼續(xù)運(yùn)行,不受影響

//exit(); //調(diào)用庫(kù)里面的exit,當(dāng)然要遵循posix的線程語(yǔ)義,所有線程退出

}

}

return 0;

}

作為最后,為了使得本文的副標(biāo)題不是空設(shè),稍微談一下linux的進(jìn)程uid等特征,前面的文章說(shuō)過(guò),linux靠uid,gid實(shí)現(xiàn)了多用戶(hù),這個(gè)多用戶(hù)是進(jìn)程意義上的,如果按照本文前面說(shuō)的概念和外延的觀點(diǎn)來(lái)看的話(huà),多用戶(hù)只是為了實(shí)現(xiàn)多用戶(hù)而必須的一個(gè)執(zhí)行緒的參數(shù)而已,其實(shí)每個(gè)執(zhí)行緒即task_struct都有一個(gè)uid和gid等信息而并不一定僅僅指進(jìn)程,如下的例子可以證明:

int handler( void *p)

{

open("/root/b",O_CREATE);

perror("open b");

setuid(500);

seteuid(500);

open("/root/c",O_CREATE);

perror("open c");

}

int main(int argc, char* argv[])

{

int i = 0;

clone(handler, &i-1024, CLONE_SIGHAND|CLONE_VM|CLONE_THREAD, NULL);

if(getchar()=="w")

{

open("/root/a",O_CREATE);

perror("open a");

}

return 0;

}

在以上的例子中,以root用戶(hù)運(yùn)行這個(gè)代碼,c的打開(kāi)將失敗,而a,b將成功,這里可以說(shuō)明在不同的線程里面可以有不同的uid和gid,其實(shí)這里的執(zhí)行緒已經(jīng)不再是線程了,這個(gè)例子再次說(shuō)明,在linux內(nèi)核中沒(méi)有線程的明確定義,再抽象一點(diǎn)其實(shí)也沒(méi)有進(jìn)程,而僅僅有執(zhí)行緒而已,這個(gè)執(zhí)行緒到底是什么,就看用戶(hù)提供什么策略使他成為什么外延了。


?本文轉(zhuǎn)自 dog250 51CTO博客,原文鏈接:http://blog.51cto.com/dog250/1273411


總結(jié)

以上是生活随笔為你收集整理的linux用户空间和内核exit的语义--linux没有线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。