? ? ? ? 上節(jié)課我們學(xué)習(xí)了幾個重要Linux命令墩莫,其實Linux命令也是一個程序厅贪,只不過代碼是別人寫的逐沙,我們直接拿過來用就好啦。
? ? ? ? 不過搏讶,無論是別人寫的程序還是我們自己寫的程序佳鳖,運(yùn)行起來都是進(jìn)程。一個進(jìn)程的運(yùn)行需要使用操作系統(tǒng)的系統(tǒng)調(diào)用服務(wù)媒惕,系統(tǒng)調(diào)用決定了這個操作系統(tǒng)好不好用系吩、功能全不全。
? ? 1進(jìn)程管理
? ? ? ? 前面我們有開玩笑說給扣扣立項妒蔚,其實對應(yīng)到Linux操作系統(tǒng)中就是創(chuàng)建進(jìn)程穿挨。
? ? ? ? 創(chuàng)建進(jìn)程的系統(tǒng)調(diào)用叫做fork,它的中文叫“分支”肴盏,為啥啟動一個新教程要叫“分支”呢科盛?
? ? ? ? 在Linux中,要創(chuàng)建一個新的進(jìn)程菜皂,需要一個老的進(jìn)程調(diào)用fork來實現(xiàn)贞绵,其中老的進(jìn)程叫做父進(jìn)程,新的進(jìn)程叫做子進(jìn)程恍飘。
? ? ? ? 當(dāng)父進(jìn)程調(diào)用fork創(chuàng)建進(jìn)程的時候榨崩,子進(jìn)程將各個[子系統(tǒng)為父進(jìn)程創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)](這個斷句很容易斷錯,嘿嘿)也全部拷貝了一份章母,甚至連程序代碼也是拷貝過來的母蛛。
? ? ? ? 但是如果父進(jìn)程和子進(jìn)程都按相同的程序代碼進(jìn)行下去,就完全沒有意義了乳怎,所以我們會做一個特殊處理:對于fork系統(tǒng)調(diào)用的返回值彩郊,如果當(dāng)前進(jìn)程是子進(jìn)程,就返回0;如果當(dāng)前進(jìn)程是父進(jìn)程秫逝,就返回子進(jìn)程的進(jìn)程號恕出。這樣首先在返回值里就有了一個區(qū)分,然后通過if-else判斷筷登,如果是父進(jìn)程剃根,還接著做原來應(yīng)該做的事情;如果是子進(jìn)程前方,需要請求另一個系統(tǒng)調(diào)用execve來執(zhí)行另一個程序狈醉,這個時候,子進(jìn)程和父進(jìn)程就徹底分道揚(yáng)鑣了惠险,也即產(chǎn)生了一個分支(fork)了苗傅。
? ? ? ? 那么問題來了,既然新進(jìn)程都是父進(jìn)程fork出來的班巩,那么第一個進(jìn)程是誰捏渣慕?
? ? ? ? 在操作系統(tǒng)中,啟動的時候會先創(chuàng)建一個所有用戶進(jìn)程的“祖宗進(jìn)程”抱慌,后面會詳細(xì)講~
? ? ? ? 有時候父進(jìn)程要關(guān)心子進(jìn)程的運(yùn)行情況逊桦,有個系統(tǒng)調(diào)用waitpid,父進(jìn)程可以調(diào)用它抑进,將子進(jìn)程的進(jìn)程號作為參數(shù)傳給它强经,這樣父進(jìn)程就知道子進(jìn)程運(yùn)行完了沒有,成功與否寺渗。
? ? ? ? 嘻嘻匿情,舉個例子,一個公司里有新員工要入職信殊,肯定要填各種表呀走各種流程之類的炬称,這時從上級的老員工的表單fork一個模板出來,然后新員工再進(jìn)行相應(yīng)的自己的修改涡拘。然后公司的第一個員工肯定是老板自己啦玲躯,他就相當(dāng)于那個“祖宗進(jìn)程”。然后老板或者新員工的上級老員工還要對自己的員工負(fù)責(zé)鳄乏,所以會關(guān)心他的進(jìn)度~
? ? 2內(nèi)存管理
? ? ? ? 進(jìn)程啟動之后府蔗,每個進(jìn)程都有自己的獨(dú)立的內(nèi)存空間呢,互相之間不干擾汞窗,叫做進(jìn)程內(nèi)存空間。
? ? ? ? 這個獨(dú)立的進(jìn)程內(nèi)存空間里赡译,都會放些什么呢仲吏?
? ? ? ? 對于進(jìn)程來說,它執(zhí)行所需依據(jù)的程序代碼肯定要放進(jìn)去,這一部分我們稱為代碼段裹唆。
? ? ? ? 另外進(jìn)程在運(yùn)行的過程中會產(chǎn)生數(shù)據(jù)誓斥,這部分我們稱為數(shù)據(jù)段。其中局部變量的部分许帐,在當(dāng)前函數(shù)執(zhí)行的時候起作用劳坑,當(dāng)進(jìn)入另一個函數(shù)時,這個變量就釋放了成畦;也有動態(tài)分配的距芬,會較長時間保存,指明才銷毀的循帐,這部分稱為堆(Heap)框仔。
? ? ? ? 一個進(jìn)程的內(nèi)存空間是很大的,32位的有4G拄养,64位的就更大了离斩,我們不可能有這么多物理內(nèi)存,它都是需要的時候再分配的瘪匿。所以跛梗,進(jìn)程要去使用部分內(nèi)存的時候,才會使用內(nèi)存管理的系統(tǒng)調(diào)用來做登記棋弥,說自己馬上要用啦核偿,需要分一部分內(nèi)存給它,而且就算這樣也不代表真的就對應(yīng)到了物理內(nèi)存嘁锯,只有真的寫入數(shù)據(jù)的時候宪祥,發(fā)現(xiàn)沒有對應(yīng)的物理內(nèi)存,才會觸發(fā)一個中斷家乘,現(xiàn)分物理內(nèi)存蝗羊。
? ? ? ? 這里介紹兩個堆里面分配內(nèi)存的系統(tǒng)調(diào)動,brk和mmap仁锯。
? ? ? ? 當(dāng)分配的內(nèi)存數(shù)量比較小的時候耀找,使用brk,回合原來的堆的數(shù)據(jù)連在一起业崖,就像給原來辦公室多搬兩把椅子一樣野芒;當(dāng)分配的內(nèi)存數(shù)量比較大的時候,使用mmap双炕,會重新劃分一塊區(qū)域狞悲,也就是說,當(dāng)辦公空間需要太多的時候妇斤,索性劃分一整塊新的辦公室摇锋。
? ? 3文件管理
? ? ? ? 在操作系統(tǒng)中丹拯,我們的程序、文檔荸恕、照片等等這些文件乖酬,即使關(guān)機(jī)再開機(jī)也不能丟掉的,所以需要將它放在文件系統(tǒng)中融求。
? ? ? ? 文件之所以可以做到這一點(diǎn)咬像,一方面是因為介質(zhì),另一方面是因為格式生宛。
? ? ? ? 文件管理其實花樣不多县昂,無非就是創(chuàng)建、打開茅糜、讀七芭、寫等。
? ? ? ? 對于文件的操作蔑赘,下面這六個系統(tǒng)調(diào)用是最重要的:
? ? ? ? 1.對于已經(jīng)有的文件狸驳,可以用open打開這個文件,close關(guān)閉這個文件缩赛。
? ? ? ? 2.對于沒有的文件耙箍,可以用create創(chuàng)建文件。
? ? ? ? 3.打開文件以后酥馍,可以使用Iseek調(diào)到文件的某個位置辩昆。
? ? ? ? 4.可以對文件的內(nèi)容進(jìn)行讀寫,讀的系統(tǒng)調(diào)用是read旨袒,寫是write汁针。
? ? ? ? 在Linux操作系統(tǒng)中,有一個重要的特點(diǎn)就是砚尽,一切皆文件施无。
? ? ? ? 比如:
? ? ? ? 啟動一個進(jìn)程,需要一個程序文件必孤,這是一個二進(jìn)制文件猾骡。
? ? ? ? 啟動的時候,要加載一些配置文件敷搪,這是文本文件兴想;啟動之后會打印一些日志,如果寫到硬盤上赡勘,也是文本文件嫂便。
? ? ? ? 如果日志打印到交互控制臺上,在命令行上刷刷的打印出來闸与,這是一個標(biāo)準(zhǔn)輸出stdout文件顽悼。
? ? ? ? 一個進(jìn)程的輸出可以作為另一個進(jìn)程的輸入曼振,這種方式稱為管道,管道也是一個文件蔚龙。
? ? ? ? 進(jìn)程可以通過網(wǎng)絡(luò)和其他進(jìn)程進(jìn)行通信,建立的Socket映胁,也是一個文件木羹。
? ? ? ? 進(jìn)程需要訪問外部設(shè)備,設(shè)備也是一個文件解孙。
? ? ? ? 文件都被存儲在文件夾里面坑填,文件夾也是一個文件。
? ? ? ? 進(jìn)程運(yùn)行起來弛姜,要想看到進(jìn)程運(yùn)行的情況脐瑰,會在/proc下面有對應(yīng)的進(jìn)程號,還是一系列文件廷臼。
? ? ? ? 每個文件苍在,Linux都會分配一個文件描述符,這是一個整數(shù)荠商。有了這個文件描述符寂恬,我們就可以使用系統(tǒng)調(diào)用,查看或者干預(yù)進(jìn)程運(yùn)行的方方面面莱没。
? ? ? ? 所以說文件操作是貫穿適中的初肉,這也是“一切皆文件”的優(yōu)勢,統(tǒng)一了操作的入口饰躲,提供了極大的便利牙咏。
? ? 4信號處理
? ? ? ? 當(dāng)進(jìn)程遇到異常情況,就需要發(fā)送一個信號嘹裂,經(jīng)常遇到的信號有以下幾種:
? ? ? ? 在執(zhí)行一個程序的時候妄壶,在鍵盤輸入“CTRL+C”,這就是中斷的信號焦蘑,正在執(zhí)行的命令就會終止退出盯拱。
? ? ? ? 非法訪問內(nèi)存,比如不小心訪問到別人家進(jìn)程的內(nèi)存空間例嘱。
? ? ? ? 硬件故障狡逢。
? ? ? ? 用戶進(jìn)程通過kill函數(shù),將一個用戶信號發(fā)送給另一個進(jìn)程拼卵。
? ? ? ? 當(dāng)“項目組”收到這些信號的時候奢浑,需要決定如何處理這些異常情況~
? ? ? ? 對于一些不嚴(yán)重的信號可以忽略,該干啥干啥腋腮,但是像SIGKILL(用于終止一個進(jìn)程的信號)和SIGSTOP(用于中止一個進(jìn)程的信號)是不能忽略的雀彼,可以執(zhí)行對于該信號的默認(rèn)動作壤蚜。
? ? ? ? 每種信號都定義了默認(rèn)的動作,例如硬件故障的默認(rèn)動作是終止徊哑。
? ? ? ? 也可以提供信號處理函數(shù)袜刷,可以通過sigaction系統(tǒng)調(diào)用,注冊一個信號處理函數(shù)莺丑。
? ? ? ? 有了信號處理服務(wù)著蟹,進(jìn)程執(zhí)行過程中一旦有變動,就可以及時的處理啦梢莽!
? ? 5進(jìn)程間通信
? ? ? ? 進(jìn)程間的溝通方式有很多種萧豆。
? ? ? ? 首先就是發(fā)個消息,這種方式稱為消息隊列昏名。我們可以通過msgget創(chuàng)建一個新的隊列涮雷,msgsnd將消息發(fā)送到消息隊列,而消息接收方可以使用msgrcv從隊列中取消息轻局。
? ? ? ? 當(dāng)兩個項目組需要交互的信息比較大的時候洪鸭,可以使用共享內(nèi)存的方式。我們可以通過shmget創(chuàng)建一個共享內(nèi)存塊嗽交,通過shmat將共享內(nèi)存映射到自己的內(nèi)存空間卿嘲,然后就可以讀寫了。但是共享內(nèi)存的時候要注意夫壁,如果大家同時修改同一數(shù)據(jù)塊就很容易出問題拾枣,所以要用到信號量的機(jī)制Semaphore,讓不同的進(jìn)程能夠排他地訪問盒让。
????6網(wǎng)絡(luò)通信
? ? ? ? 不同的操作系統(tǒng)間的通信是通過網(wǎng)絡(luò)通信進(jìn)行的梅肤,他們要遵循相同的網(wǎng)絡(luò)協(xié)議,也即TCP/IP網(wǎng)絡(luò)協(xié)議棧邑茄。Linux內(nèi)核里有對于網(wǎng)絡(luò)協(xié)議棧的實現(xiàn)姨蝴。那么它是如何暴露出服務(wù)給項目組使用捏?
? ? ? ? 網(wǎng)絡(luò)服務(wù)是通過套接字Socket來提供服務(wù)的肺缕。Socket可以作“插口”或者”插槽“講左医。我們可以想象一個畫面,弄一根網(wǎng)線同木,一頭插在客戶端浮梢,一頭插在服務(wù)端,然后進(jìn)行通信彤路。因此秕硝,在通信之前,雙方都要建立一個Socket洲尊。
? ? ? ? 我們可以通過Socket系統(tǒng)調(diào)用建立一個Socket远豺,Socket也是一個文件奈偏,也有一個文件描述符,也可以通過讀寫函數(shù)進(jìn)行通信躯护。
? ? ? ? 好了惊来,今天我們主要就了解一下這六個系統(tǒng)調(diào)用,但是這只是很小的一部分棺滞,實際上Linux中的系統(tǒng)調(diào)用非常多唁盏,我們可以在https://www.kernel.org下載一份Linux內(nèi)核源碼。
????7Glibc“中介”
? ? ? ? 做過開發(fā)的小伙伴應(yīng)該都發(fā)現(xiàn)了检眯,剛才講的系統(tǒng)調(diào)用和我們平時調(diào)用的函數(shù)不太樣。這是因為昆淡,我們平常并沒有直接使用系統(tǒng)調(diào)用锰瘸,而是使用的“中介”,這個中介就是Glibc昂灵。
? ? ? ? 有了Glibc避凝,有事情找它就行,它會轉(zhuǎn)換成為系統(tǒng)調(diào)用眨补,幫我們調(diào)用管削。
? ? ? ? Glibc是Linux下使用的開源的標(biāo)準(zhǔn)C庫,它是GNU發(fā)布的libc庫撑螺。Glibc為程序員提供豐富的API含思,除了例如字符串處理、數(shù)學(xué)運(yùn)算等用戶態(tài)服務(wù)外甘晤,最重要的是封裝了操作系統(tǒng)提供的系統(tǒng)服務(wù)含潘,即系統(tǒng)調(diào)用的封裝。
? ? ? ? 每個特定的系統(tǒng)調(diào)用對應(yīng)了至少一個Glibc封裝的庫函數(shù)线婚,比如說遏弱,系統(tǒng)提供的打開文件系統(tǒng)調(diào)用sys_open對應(yīng)的是Glibc中的open函數(shù)。
? ? ? ? 有時Glibc一個單獨(dú)的API可能調(diào)用多個系統(tǒng)調(diào)用塞弊,比如Glibc提供的printf函數(shù)就會調(diào)用如sys_open漱逸、sys_mmap、sys_write游沿、sys_close等等系統(tǒng)調(diào)用饰抒。
? ? ? ? 也有時多個API可能只對應(yīng)同一個系統(tǒng)調(diào)用,如Glibc下實現(xiàn)的malloc奏候、calloc循集、free等函數(shù)用來分配和釋放內(nèi)存,都利用了內(nèi)核的sys_brk的系統(tǒng)調(diào)用蔗草。
? ? 8總結(jié)
? ? ? ? 話不多述咒彤,看圖~