最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Linux基礎(chǔ)(二)——多進(jìn)程開(kāi)發(fā)

2023-06-05 18:07 作者:UCLmsc  | 我要投稿

一、進(jìn)程概述

程序是一組指令的有序集合,是一個(gè)靜態(tài)的概念,它是存儲(chǔ)在磁盤或其他存儲(chǔ)設(shè)備上的可執(zhí)行文件。程序本身并不占用計(jì)算機(jī)的資源,只有在運(yùn)行時(shí)才會(huì)被加載到內(nèi)存中。

進(jìn)程是指在計(jì)算機(jī)中正在運(yùn)行的程序?qū)嶓w,它包含了程序代碼、數(shù)據(jù)和執(zhí)行狀態(tài)等信息。進(jìn)程是動(dòng)態(tài)的,它需要占用計(jì)算機(jī)的資源,例如內(nèi)存、CPU 時(shí)間、I/O 等。

因此,程序和進(jìn)程之間的關(guān)系可以類比為藍(lán)圖和建筑物的關(guān)系。程序就像是藍(lán)圖,描述了建筑物的設(shè)計(jì)和構(gòu)造,而進(jìn)程就像建筑物本身,是根據(jù)藍(lán)圖所描述的設(shè)計(jì)和構(gòu)造而實(shí)際建造出來(lái)的。

總之,程序是靜態(tài)的,而進(jìn)程是動(dòng)態(tài)的。程序需要被加載到內(nèi)存中并被操作系統(tǒng)管理成為進(jìn)程,才能夠在計(jì)算機(jī)上運(yùn)行。
單道程序設(shè)計(jì)(Single-Programmed Batch System)和多道程序設(shè)計(jì)(Multi-Programmed Batch System)是兩種不同的計(jì)算機(jī)程序設(shè)計(jì)方式。

單道程序設(shè)計(jì)是指在計(jì)算機(jī)系統(tǒng)中每次只能運(yùn)行一個(gè)程序,程序運(yùn)行結(jié)束后才能運(yùn)行下一個(gè)程序。這種方式需要用戶手動(dòng)將程序輸入計(jì)算機(jī),計(jì)算機(jī)完成一個(gè)程序的執(zhí)行后,用戶再將下一個(gè)程序輸入計(jì)算機(jī)。這種方式效率低下,且無(wú)法充分利用計(jì)算機(jī)資源。

而多道程序設(shè)計(jì)是指在計(jì)算機(jī)系統(tǒng)中同時(shí)運(yùn)行多個(gè)程序,這些程序可以共享計(jì)算機(jī)的資源(如CPU、內(nèi)存等),通過(guò)操作系統(tǒng)的調(diào)度算法來(lái)控制各個(gè)程序的執(zhí)行順序和資源使用。多道程序設(shè)計(jì)能夠更好地利用計(jì)算機(jī)資源,提高計(jì)算機(jī)系統(tǒng)的吞吐量和響應(yīng)速度。

在多道程序設(shè)計(jì)中,操作系統(tǒng)將所有需要執(zhí)行的程序分成多個(gè)作業(yè),每個(gè)作業(yè)都包含一個(gè)或多個(gè)獨(dú)立的程序,這些程序可以并發(fā)執(zhí)行。作業(yè)之間的切換由操作系統(tǒng)負(fù)責(zé),操作系統(tǒng)會(huì)根據(jù)程序的優(yōu)先級(jí)、資源需求等因素來(lái)分配計(jì)算機(jī)資源,以達(dá)到最優(yōu)的執(zhí)行效果。

總之,單道程序設(shè)計(jì)和多道程序設(shè)計(jì)是兩種不同的程序設(shè)計(jì)方式,前者每次只能運(yùn)行一個(gè)程序,效率低下,而后者可以同時(shí)運(yùn)行多個(gè)程序,提高計(jì)算機(jī)系統(tǒng)的效率和吞吐量。
時(shí)間片是指在多道程序設(shè)計(jì)中,操作系統(tǒng)將CPU時(shí)間劃分為若干個(gè)時(shí)間段,每個(gè)時(shí)間段稱為一個(gè)時(shí)間片,每個(gè)進(jìn)程在一個(gè)時(shí)間片內(nèi)運(yùn)行一段時(shí)間。當(dāng)一個(gè)時(shí)間片用完后,操作系統(tǒng)會(huì)將CPU資源分配給下一個(gè)進(jìn)程,直到所有進(jìn)程都運(yùn)行完畢。

時(shí)間片的引入可以使得多個(gè)進(jìn)程在同一時(shí)間內(nèi)并發(fā)運(yùn)行,并且可以讓每個(gè)進(jìn)程都有足夠的機(jī)會(huì)使用CPU資源。時(shí)間片的大小通常由操作系統(tǒng)根據(jù)系統(tǒng)負(fù)載、進(jìn)程優(yōu)先級(jí)等因素動(dòng)態(tài)調(diào)整,以保證系統(tǒng)的響應(yīng)速度和吞吐量。

使用時(shí)間片的優(yōu)點(diǎn)是:
提高系統(tǒng)的并發(fā)性和響應(yīng)速度,避免進(jìn)程長(zhǎng)時(shí)間等待資源。
充分利用CPU資源,提高系統(tǒng)的吞吐量。
可以讓每個(gè)進(jìn)程都有機(jī)會(huì)使用CPU資源,避免某些進(jìn)程長(zhǎng)時(shí)間占用CPU,導(dǎo)致其他進(jìn)程無(wú)法運(yùn)行。
但是,時(shí)間片過(guò)小會(huì)導(dǎo)致進(jìn)程頻繁切換,增加系統(tǒng)開(kāi)銷;時(shí)間片過(guò)大會(huì)導(dǎo)致進(jìn)程響應(yīng)速度變慢,影響用戶體驗(yàn)。因此,操作系統(tǒng)需要根據(jù)實(shí)際情況動(dòng)態(tài)調(diào)整時(shí)間片的大小,以達(dá)到最優(yōu)的系統(tǒng)性能。
在Linux操作系統(tǒng)中,并行和并發(fā)是兩個(gè)重要的概念,它們有著不同的含義。

并行(Parallel)指的是多個(gè)任務(wù)同時(shí)執(zhí)行,即多個(gè)任務(wù)在同一時(shí)刻同時(shí)進(jìn)行。在Linux中,如果系統(tǒng)有多個(gè)CPU或CPU核心,那么多個(gè)進(jìn)程或線程可以在不同的CPU或核心上同時(shí)執(zhí)行,從而實(shí)現(xiàn)并行處理,提高系統(tǒng)的處理速度和吞吐量。

并發(fā)(Concurrency)指的是多個(gè)任務(wù)交替執(zhí)行,即多個(gè)任務(wù)在一段時(shí)間內(nèi)交替進(jìn)行。在Linux中,多個(gè)進(jìn)程或線程可以在同一CPU或核心上交替執(zhí)行,從而實(shí)現(xiàn)并發(fā)處理。在并發(fā)處理中,操作系統(tǒng)會(huì)根據(jù)調(diào)度算法來(lái)決定哪個(gè)進(jìn)程或線程優(yōu)先執(zhí)行,從而實(shí)現(xiàn)任務(wù)的調(diào)度和管理。

可以看出,并行和并發(fā)都是多任務(wù)處理的方式,但是它們的實(shí)現(xiàn)方式不同。并行需要多個(gè)CPU或核心的支持,而并發(fā)可以在單個(gè)CPU或核心上實(shí)現(xiàn)。并行處理可以提高系統(tǒng)的處理能力和效率,但需要硬件支持;而并發(fā)處理可以提高系統(tǒng)的響應(yīng)速度和資源利用率,但需要考慮并發(fā)訪問(wèn)帶來(lái)的同步和競(jìng)爭(zhēng)問(wèn)題。

總之,并行和并發(fā)是兩種不同的多任務(wù)處理方式,它們都有著自己的優(yōu)點(diǎn)和適用場(chǎng)景,需要根據(jù)實(shí)際情況選擇合適的方式來(lái)進(jìn)行多任務(wù)處理。
在Linux操作系統(tǒng)中,進(jìn)程控制塊(Process Control Block,PCB)是內(nèi)核用來(lái)管理和維護(hù)進(jìn)程信息的數(shù)據(jù)結(jié)構(gòu)。每個(gè)進(jìn)程都有一個(gè)對(duì)應(yīng)的PCB,PCB中包含了進(jìn)程的很多信息,如進(jìn)程狀態(tài)、進(jìn)程ID、程序計(jì)數(shù)器、棧指針、寄存器狀態(tài)、進(jìn)程優(yōu)先級(jí)、進(jìn)程所屬用戶等等。

在Linux中,PCB是由內(nèi)核動(dòng)態(tài)分配的,當(dāng)進(jìn)程創(chuàng)建時(shí),內(nèi)核會(huì)為進(jìn)程分配一塊內(nèi)存,用來(lái)存儲(chǔ)PCB信息。每個(gè)PCB都有一個(gè)唯一的進(jìn)程ID,用來(lái)標(biāo)識(shí)該進(jìn)程。當(dāng)進(jìn)程執(zhí)行時(shí),內(nèi)核會(huì)根據(jù)PCB中的信息來(lái)管理和控制進(jìn)程的行為,例如調(diào)度進(jìn)程、分配資源、進(jìn)行系統(tǒng)調(diào)用等等。

Linux中的PCB包含了很多信息,這些信息可以分為以下幾個(gè)方面:
進(jìn)程標(biāo)識(shí)信息:進(jìn)程ID、進(jìn)程優(yōu)先級(jí)、進(jìn)程所屬用戶等。
進(jìn)程狀態(tài)信息:進(jìn)程狀態(tài)、進(jìn)程調(diào)度信息、CPU時(shí)間等。
進(jìn)程內(nèi)存信息:進(jìn)程地址空間、虛擬內(nèi)存映射等。
進(jìn)程文件信息:進(jìn)程打開(kāi)的文件、文件描述符等。

通過(guò)PCB,內(nèi)核可以對(duì)進(jìn)程進(jìn)行管理和控制,例如對(duì)進(jìn)程進(jìn)行調(diào)度、分配資源、中斷處理等。同時(shí),PCB也是進(jìn)程之間通信和同步的重要手段,進(jìn)程可以通過(guò)PCB來(lái)訪問(wèn)和修改其他進(jìn)程的信息,實(shí)現(xiàn)進(jìn)程之間的通信和同步。

二、進(jìn)程狀態(tài)轉(zhuǎn)換

在Linux操作系統(tǒng)中,進(jìn)程狀態(tài)轉(zhuǎn)換通常有以下5種狀態(tài):

新建狀態(tài)(New):當(dāng)一個(gè)進(jìn)程被創(chuàng)建時(shí),它處于新建狀態(tài)。此時(shí),操作系統(tǒng)會(huì)為該進(jìn)程分配資源并初始化進(jìn)程控制塊(PCB)。

就緒狀態(tài)(Ready):當(dāng)進(jìn)程已經(jīng)準(zhǔn)備好運(yùn)行,但由于CPU資源正在被其他進(jìn)程占用,因此它不能立即運(yùn)行,此時(shí)進(jìn)程處于就緒狀態(tài)。

運(yùn)行狀態(tài)(Running):當(dāng)進(jìn)程被分配到CPU資源并開(kāi)始執(zhí)行時(shí),它處于運(yùn)行狀態(tài)。此時(shí)進(jìn)程正在使用CPU資源進(jìn)行計(jì)算、I/O操作等。

阻塞狀態(tài)(Blocked):當(dāng)進(jìn)程需要等待某些事件發(fā)生(如I/O操作完成、信號(hào)到達(dá)等),而這些事件不能立即發(fā)生時(shí),進(jìn)程會(huì)進(jìn)入阻塞狀態(tài)。此時(shí),操作系統(tǒng)會(huì)將進(jìn)程從CPU資源中移除,直到事件發(fā)生后才會(huì)重新將其調(diào)入就緒狀態(tài)。

終止?fàn)顟B(tài)(Terminated):當(dāng)進(jìn)程執(zhí)行完成或被強(qiáng)制終止時(shí),它會(huì)進(jìn)入終止?fàn)顟B(tài)。此時(shí),操作系統(tǒng)會(huì)釋放進(jìn)程占用的資源,并從系統(tǒng)進(jìn)程列表中刪除該進(jìn)程。

在進(jìn)程的生命周期中,進(jìn)程狀態(tài)會(huì)不斷地發(fā)生變化,通常的狀態(tài)轉(zhuǎn)換為:

New -> Ready -> Running -> Blocked -> Ready -> Running -> ... -> Terminated

其中,就緒狀態(tài)、運(yùn)行狀態(tài)和阻塞狀態(tài)都是進(jìn)程運(yùn)行的三種基本狀態(tài),它們之間的切換由操作系統(tǒng)的調(diào)度算法來(lái)決定,以實(shí)現(xiàn)對(duì)進(jìn)程的管理和調(diào)度。

總之,Linux中進(jìn)程狀態(tài)轉(zhuǎn)換是進(jìn)程生命周期中重要的一部分,了解進(jìn)程狀態(tài)的變化可以幫助我們更好地理解進(jìn)程的執(zhí)行過(guò)程和操作系統(tǒng)的工作原理。
ps:用于查看當(dāng)前系統(tǒng)中的進(jìn)程信息,可以顯示進(jìn)程ID、進(jìn)程狀態(tài)、進(jìn)程所屬用戶等。

top:用于實(shí)時(shí)監(jiān)控進(jìn)程的狀態(tài)和系統(tǒng)資源使用情況,可以顯示CPU、內(nèi)存、I/O等信息。

kill:用于向進(jìn)程發(fā)送信號(hào),可以用來(lái)終止進(jìn)程、重啟進(jìn)程、暫停進(jìn)程等。

pkill:用于根據(jù)進(jìn)程名或其他屬性殺死進(jìn)程,可以通過(guò)正則表達(dá)式等方式指定進(jìn)程。

killall:用于根據(jù)進(jìn)程名殺死進(jìn)程,可以殺死所有同名進(jìn)程。

nice:用于設(shè)置進(jìn)程的優(yōu)先級(jí),可以讓進(jìn)程使用更多或更少的CPU資源。

renice:用于修改已經(jīng)運(yùn)行的進(jìn)程的優(yōu)先級(jí)。

top、htop:用于監(jiān)控系統(tǒng)資源使用情況和進(jìn)程狀態(tài),可以實(shí)時(shí)顯示進(jìn)程的CPU、內(nèi)存、I/O等信息。

vmstat:用于監(jiān)控系統(tǒng)資源使用情況,可以顯示CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)等信息。

pidof:用于根據(jù)進(jìn)程名獲取進(jìn)程ID。
在Linux操作系統(tǒng)中,每個(gè)進(jìn)程都有一個(gè)唯一的進(jìn)程ID(Process ID,PID),用于標(biāo)識(shí)該進(jìn)程。進(jìn)程號(hào)是一個(gè)非負(fù)整數(shù),通常情況下,進(jìn)程號(hào)從1開(kāi)始,每創(chuàng)建一個(gè)新的進(jìn)程,進(jìn)程號(hào)就會(huì)遞增1。

在Linux中,進(jìn)程號(hào)的獲取和管理可以通過(guò)以下幾個(gè)系統(tǒng)調(diào)用函數(shù)來(lái)實(shí)現(xiàn):

getpid():獲取當(dāng)前進(jìn)程的進(jìn)程ID。

getppid():獲取當(dāng)前進(jìn)程的父進(jìn)程ID。

fork():創(chuàng)建一個(gè)新的進(jìn)程,新進(jìn)程的進(jìn)程ID不同于父進(jìn)程的進(jìn)程ID。

exec():在當(dāng)前進(jìn)程中執(zhí)行一個(gè)新的程序,進(jìn)程ID不會(huì)改變。

wait():等待指定進(jìn)程退出,獲取該進(jìn)程的退出狀態(tài)。

kill():向指定進(jìn)程發(fā)送信號(hào),可以用來(lái)終止進(jìn)程、重啟進(jìn)程、暫停進(jìn)程等。

signal():設(shè)置或處理信號(hào)處理函數(shù),可以用來(lái)處理進(jìn)程接收到的信號(hào)。

除了以上這些系統(tǒng)調(diào)用函數(shù),還有一些其他的函數(shù)可以用來(lái)獲取和管理進(jìn)程信息,例如:

ps:用于顯示當(dāng)前系統(tǒng)中的進(jìn)程信息,包括進(jìn)程ID、進(jìn)程狀態(tài)等。

top:用于實(shí)時(shí)監(jiān)控進(jìn)程的狀態(tài)和系統(tǒng)資源使用情況。

htop:類似于top,但是可以使用鼠標(biāo)和鍵盤進(jìn)行交互。

pstree:用于顯示進(jìn)程之間的關(guān)系,以樹狀結(jié)構(gòu)的形式展示。

lsof:用于顯示系統(tǒng)中打開(kāi)的文件和進(jìn)程信息。

通過(guò)這些函數(shù)和命令,我們可以獲取和管理進(jìn)程信息,了解系統(tǒng)的運(yùn)行狀態(tài)和資源使用情況,進(jìn)行調(diào)試和優(yōu)化。

三、進(jìn)程創(chuàng)建

在Linux中,進(jìn)程的創(chuàng)建是通過(guò)fork()系統(tǒng)調(diào)用實(shí)現(xiàn)的。fork()系統(tǒng)調(diào)用將創(chuàng)建一個(gè)與父進(jìn)程完全相同的子進(jìn)程。子進(jìn)程將復(fù)制父進(jìn)程的數(shù)據(jù)、堆棧和代碼段等內(nèi)容,并且在一個(gè)獨(dú)立的地址空間中運(yùn)行。

當(dāng)進(jìn)程調(diào)用fork()時(shí),操作系統(tǒng)會(huì)為子進(jìn)程創(chuàng)建一個(gè)新的進(jìn)程描述符,并為其分配一個(gè)唯一的進(jìn)程ID。子進(jìn)程將繼承父進(jìn)程的打開(kāi)文件描述符、信號(hào)處理程序等信息。父進(jìn)程和子進(jìn)程之間的區(qū)別在于返回值:在父進(jìn)程中,fork()將返回子進(jìn)程的進(jìn)程ID,而在子進(jìn)程中,返回值將為0。

在子進(jìn)程中,通常緊接著會(huì)調(diào)用exec()系列函數(shù),以便將子進(jìn)程替換為另一個(gè)可執(zhí)行文件。這將導(dǎo)致子進(jìn)程的地址空間被新程序所占用。

四、父子進(jìn)程虛擬地址空間情況

在Linux中,父進(jìn)程和子進(jìn)程在創(chuàng)建時(shí)共享相同的物理內(nèi)存,但是它們各自擁有獨(dú)立的虛擬地址空間。虛擬地址空間是每個(gè)進(jìn)程獨(dú)立的地址空間,它將進(jìn)程所需的內(nèi)存映射到物理內(nèi)存中,使得每個(gè)進(jìn)程都可以獨(dú)立地訪問(wèn)它的內(nèi)存空間。

在創(chuàng)建子進(jìn)程時(shí),操作系統(tǒng)將為子進(jìn)程復(fù)制父進(jìn)程的整個(gè)虛擬地址空間,包括代碼段、數(shù)據(jù)段、堆和棧等內(nèi)容。子進(jìn)程的虛擬地址空間是父進(jìn)程虛擬地址空間的一個(gè)副本,但是子進(jìn)程的虛擬地址空間是獨(dú)立的,因此父進(jìn)程和子進(jìn)程之間不會(huì)相互干擾。

當(dāng)一個(gè)進(jìn)程修改它的虛擬地址空間時(shí),它的修改只會(huì)影響到它自己的虛擬地址空間,不會(huì)影響到其他進(jìn)程的虛擬地址空間。例如,當(dāng)一個(gè)進(jìn)程分配內(nèi)存時(shí),它只會(huì)修改自己的虛擬地址空間,不會(huì)影響其他進(jìn)程的虛擬地址空間。因此,每個(gè)進(jìn)程都可以獨(dú)立地管理它自己的虛擬地址空間,這是多個(gè)進(jìn)程能夠同時(shí)運(yùn)行的重要基礎(chǔ)。

在父進(jìn)程和子進(jìn)程中,相同的虛擬地址通常都會(huì)映射到相同的物理內(nèi)存區(qū)域。這意味著,如果一個(gè)進(jìn)程修改了它的虛擬地址空間中的某個(gè)變量,那么另一個(gè)進(jìn)程也會(huì)看到這個(gè)變量的值發(fā)生了改變。但是,由于每個(gè)進(jìn)程都有自己的虛擬地址空間,因此它們之間的變量并不是真正共享的,它們只是在物理內(nèi)存中的同一位置上有相同的副本而已。

五、父子進(jìn)程關(guān)系及GDB多進(jìn)程調(diào)試

在Linux中,父進(jìn)程和子進(jìn)程之間的關(guān)系是一種典型的父子關(guān)系。當(dāng)一個(gè)進(jìn)程調(diào)用fork()系統(tǒng)調(diào)用時(shí),它將創(chuàng)建一個(gè)與自己幾乎完全相同的子進(jìn)程。子進(jìn)程將繼承父進(jìn)程的地址空間、打開(kāi)的文件描述符和信號(hào)處理程序等信息。父進(jìn)程和子進(jìn)程是兩個(gè)獨(dú)立的進(jìn)程,它們各自獨(dú)立地運(yùn)行,但是它們之間也存在一些共享的資源和通信機(jī)制,例如管道、共享內(nèi)存和信號(hào)等。
在GDB中,可以使用set follow-fork-mode命令來(lái)控制如何跟蹤子進(jìn)程。該命令有三個(gè)選項(xiàng):

parent:跟蹤父進(jìn)程,子進(jìn)程將在后臺(tái)運(yùn)行;
child:跟蹤子進(jìn)程,父進(jìn)程將在后臺(tái)運(yùn)行;
ask:每次fork()調(diào)用時(shí)詢問(wèn)用戶應(yīng)該跟蹤哪個(gè)進(jìn)程。
默認(rèn)情況下,GDB使用parent選項(xiàng)來(lái)跟蹤進(jìn)程。如果要跟蹤子進(jìn)程,可以使用set follow-fork-mode child命令。

在GDB中進(jìn)行多進(jìn)程調(diào)試時(shí),可以使用set detach-on-fork命令來(lái)控制子進(jìn)程的行為。如果將其設(shè)置為off,則子進(jìn)程將繼續(xù)在GDB中運(yùn)行;如果將其設(shè)置為on,則子進(jìn)程將自動(dòng)與GDB斷開(kāi)連接,并在后臺(tái)運(yùn)行。默認(rèn)情況下,set detach-on-fork命令的值為on。

在多進(jìn)程調(diào)試中,可以使用info inferiors命令來(lái)列出所有的進(jìn)程。使用inferior命令可以選擇當(dāng)前要調(diào)試的進(jìn)程。在選擇了進(jìn)程后,可以使用info threads命令來(lái)列出該進(jìn)程中的所有線程。使用thread命令可以選擇要調(diào)試的線程。在選擇了線程后,可以像調(diào)試單個(gè)進(jìn)程一樣使用GDB進(jìn)行調(diào)試。

六、exec函數(shù)族

在Linux中,exec()函數(shù)族是一組用于在當(dāng)前進(jìn)程中執(zhí)行新程序的函數(shù)。這些函數(shù)將在當(dāng)前進(jìn)程的地址空間中加載一個(gè)新的可執(zhí)行文件,并且替換當(dāng)前進(jìn)程的代碼段、數(shù)據(jù)段和堆棧等內(nèi)容,從而使得當(dāng)前進(jìn)程以新程序的身份繼續(xù)運(yùn)行。

exec()函數(shù)族包括以下函數(shù):

int execl(const char *path, const char *arg, ...);:通過(guò)指定可執(zhí)行文件的路徑和命令行參數(shù),執(zhí)行一個(gè)新程序。arg參數(shù)和后續(xù)的可變參數(shù)都是新程序的命令行參數(shù),最后一個(gè)參數(shù)必須是NULL。
int execv(const char *path, char *const argv[]);:與execl()函數(shù)類似,但是參數(shù)以字符串?dāng)?shù)組的形式傳遞給新程序。
int execle(const char *path, const char *arg, ..., char *const envp[]);:與execl()函數(shù)類似,但是可以指定新程序的環(huán)境變量。
int execve(const char *path, char *const argv[], char *const envp[]);:與execv()函數(shù)類似,但是可以指定新程序的環(huán)境變量。
int execlp(const char *file, const char *arg, ...);:與execl()函數(shù)類似,但是可執(zhí)行文件的路徑不需要指定絕對(duì)路徑,而是在PATH環(huán)境變量中搜索可執(zhí)行文件。
int execvp(const char *file, char *const argv[]);:與execv()函數(shù)類似,但是可執(zhí)行文件的路徑不需要指定絕對(duì)路徑,而是在PATH環(huán)境變量中搜索可執(zhí)行文件。
exec()函數(shù)族的返回值只有在執(zhí)行失敗時(shí)才會(huì)返回,如果執(zhí)行成功,則不會(huì)返回。如果exec()函數(shù)執(zhí)行失敗,它將返回-1,并設(shè)置errno變量來(lái)指示錯(cuò)誤的類型。

注意,在exec()函數(shù)族中,新程序?qū)?huì)繼承當(dāng)前進(jìn)程的一些屬性,例如文件描述符和信號(hào)處理程序等。因此,在調(diào)用exec()函數(shù)族之前,通常需要使用fork()函數(shù)創(chuàng)建一個(gè)新進(jìn)程,以便在子進(jìn)程中調(diào)用exec()函數(shù)族,從而保持父進(jìn)程不受影響。

七、進(jìn)程退出、孤兒進(jìn)程、僵尸進(jìn)程

在Linux中,進(jìn)程退出可以通過(guò)調(diào)用exit()函數(shù)或者發(fā)送SIGTERM信號(hào)來(lái)實(shí)現(xiàn)。調(diào)用exit()函數(shù)將會(huì)使進(jìn)程正常退出并返回一個(gè)退出碼,這個(gè)退出碼可以被父進(jìn)程使用wait()函數(shù)獲取。發(fā)送SIGTERM信號(hào)將會(huì)強(qiáng)制終止進(jìn)程,并且不會(huì)返回任何退出碼。
當(dāng)一個(gè)進(jìn)程的父進(jìn)程先于它退出時(shí),這個(gè)進(jìn)程就會(huì)成為孤兒進(jìn)程。孤兒進(jìn)程將會(huì)被init進(jìn)程接管,并且init進(jìn)程將會(huì)成為它的新父進(jìn)程。init進(jìn)程是系統(tǒng)中第一個(gè)啟動(dòng)的進(jìn)程,它會(huì)周期性地調(diào)用wait()函數(shù)來(lái)等待孤兒進(jìn)程的退出,并且釋放孤兒進(jìn)程的資源。
當(dāng)一個(gè)進(jìn)程退出時(shí),它的退出狀態(tài)信息會(huì)被保留在系統(tǒng)中,直到它的父進(jìn)程調(diào)用wait()或waitpid()函數(shù)來(lái)獲取它的退出狀態(tài)信息為止。如果父進(jìn)程沒(méi)有及時(shí)地調(diào)用wait()或waitpid()函數(shù),那么這個(gè)進(jìn)程的狀態(tài)信息就會(huì)一直被保留在系統(tǒng)中,這個(gè)進(jìn)程就會(huì)成為一個(gè)僵尸進(jìn)程。

僵尸進(jìn)程并不會(huì)占用系統(tǒng)資源,但是它們會(huì)占用一定的進(jìn)程ID和進(jìn)程描述符等資源。如果系統(tǒng)中有大量的僵尸進(jìn)程,就會(huì)導(dǎo)致系統(tǒng)資源的浪費(fèi)。為了避免僵尸進(jìn)程的產(chǎn)生,父進(jìn)程通常需要在子進(jìn)程退出時(shí)調(diào)用wait()或waitpid()函數(shù)來(lái)獲取它的退出狀態(tài)信息,并且釋放子進(jìn)程的資源。如果父進(jìn)程不再需要子進(jìn)程的狀態(tài)信息,也可以使用waitpid()函數(shù)的WNOHANG選項(xiàng)來(lái)非阻塞地獲取子進(jìn)程的狀態(tài)信息。如果父進(jìn)程不希望等待子進(jìn)程退出,也可以使用SIGCHLD信號(hào)來(lái)異步地處理子進(jìn)程的退出狀態(tài)信息。

八、wait函數(shù)

在Linux中,當(dāng)一個(gè)進(jìn)程退出時(shí),它的一些資源需要被回收,否則會(huì)導(dǎo)致資源泄漏或者系統(tǒng)資源耗盡。主要的資源包括進(jìn)程ID、進(jìn)程描述符、內(nèi)存空間、打開(kāi)的文件描述符等。

Linux中的進(jìn)程回收是通過(guò)父進(jìn)程調(diào)用wait()或waitpid()函數(shù)來(lái)實(shí)現(xiàn)的。這些函數(shù)會(huì)阻塞父進(jìn)程,直到一個(gè)子進(jìn)程退出,然后返回子進(jìn)程的進(jìn)程ID和退出狀態(tài)信息。父進(jìn)程可以使用這些信息來(lái)釋放子進(jìn)程的資源,并且避免子進(jìn)程成為僵尸進(jìn)程。如果父進(jìn)程不希望阻塞,也可以使用waitpid()函數(shù)的WNOHANG選項(xiàng)來(lái)非阻塞地獲取子進(jìn)程的狀態(tài)信息。

當(dāng)一個(gè)進(jìn)程退出時(shí),它的退出狀態(tài)信息會(huì)被保存在內(nèi)核中,直到它的父進(jìn)程調(diào)用wait()或waitpid()函數(shù)來(lái)獲取。如果一個(gè)進(jìn)程沒(méi)有父進(jìn)程,或者其父進(jìn)程已經(jīng)退出,那么這個(gè)進(jìn)程就會(huì)被init進(jìn)程接管,init進(jìn)程將會(huì)周期性地調(diào)用wait()函數(shù)來(lái)獲取孤兒進(jìn)程的退出狀態(tài)信息,并且釋放它們的資源。

進(jìn)程回收還包括釋放進(jìn)程占用的內(nèi)存空間和其他資源。當(dāng)一個(gè)進(jìn)程退出時(shí),它占用的內(nèi)存空間會(huì)被操作系統(tǒng)回收,這些空間可以被分配給其他進(jìn)程使用。同時(shí),打開(kāi)的文件描述符等其他資源也會(huì)被釋放,以便下一個(gè)進(jìn)程可以使用它們。

總之,進(jìn)程回收是Linux系統(tǒng)中一個(gè)重要的機(jī)制,它可以幫助操作系統(tǒng)有效地管理進(jìn)程和資源,從而提高系統(tǒng)的穩(wěn)定性和性能。

九、waitpid函數(shù)

WIFEXITED(status):如果進(jìn)程正常退出,則返回非零值。
WEXITSTATUS(status):如果進(jìn)程正常退出,則返回進(jìn)程的退出狀態(tài)碼。
WIFSIGNALED(status):如果進(jìn)程是因?yàn)樾盘?hào)而退出,則返回非零值。
WTERMSIG(status):如果進(jìn)程是因?yàn)樾盘?hào)而退出,則返回導(dǎo)致進(jìn)程退出的信號(hào)編號(hào)。
WCOREDUMP(status):如果進(jìn)程是因?yàn)樾盘?hào)而退出,并且產(chǎn)生了核心轉(zhuǎn)儲(chǔ)文件,則返回非零值。
WIFSTOPPED(status):如果進(jìn)程被暫停,則返回非零值。
WSTOPSIG(status):如果進(jìn)程被暫停,則返回導(dǎo)致進(jìn)程暫停的信號(hào)編號(hào)。
WIFCONTINUED(status):如果進(jìn)程被恢復(fù),則返回非零值。
pid參數(shù)指定要等待的子進(jìn)程的進(jìn)程ID。如果pid為-1,則表示等待任意子進(jìn)程退出。如果pid大于0,則表示等待指定進(jìn)程ID的子進(jìn)程退出。如果pid為0,則表示等待與當(dāng)前進(jìn)程在同一進(jìn)程組中的任意子進(jìn)程退出。

status參數(shù)是一個(gè)整型指針,用于保存子進(jìn)程的退出狀態(tài)信息。如果不關(guān)心子進(jìn)程的退出狀態(tài)信息,可以將status設(shè)置為NULL。

options參數(shù)指定等待子進(jìn)程的行為。常用的選項(xiàng)包括:

WNOHANG:非阻塞模式,即如果沒(méi)有子進(jìn)程退出,則立即返回0,而不會(huì)阻塞。
WUNTRACED:如果子進(jìn)程處于暫停狀態(tài),則也返回狀態(tài)信息。
WCONTINUED:如果子進(jìn)程被恢復(fù),則也返回狀態(tài)信息。
waitpid()函數(shù)的返回值是退出的子進(jìn)程的進(jìn)程ID,如果沒(méi)有子進(jìn)程退出,則返回0。如果出錯(cuò),則返回-1,并設(shè)置全局變量errno表示錯(cuò)誤原因。

十、進(jìn)程間通信簡(jiǎn)介

進(jìn)程間通信可以通過(guò)以下幾種方式實(shí)現(xiàn):

管道(Pipe):管道是一種半雙工的通信方式,它只能在具有父子關(guān)系的進(jìn)程之間使用。管道有兩種類型:有名管道和無(wú)名管道。有名管道可以在不具有父子關(guān)系的進(jìn)程之間使用,而無(wú)名管道只能在具有父子關(guān)系的進(jìn)程之間使用。

命名管道(FIFO):命名管道是一種有名管道,它允許不具有父子關(guān)系的進(jìn)程之間進(jìn)行通信。命名管道可以在文件系統(tǒng)中創(chuàng)建一個(gè)特殊文件來(lái)實(shí)現(xiàn)。

信號(hào)(Signal):信號(hào)是一種異步通信方式,它允許進(jìn)程向其他進(jìn)程發(fā)送信號(hào),以通知它們發(fā)生了某些事件。信號(hào)可以用于進(jìn)程間的同步和異步通信。

共享內(nèi)存(Shared Memory):共享內(nèi)存是一種通過(guò)共享內(nèi)存區(qū)域來(lái)實(shí)現(xiàn)進(jìn)程間通信的方式,多個(gè)進(jìn)程可以訪問(wèn)同一個(gè)內(nèi)存區(qū)域,從而實(shí)現(xiàn)數(shù)據(jù)共享。共享內(nèi)存通常需要配合信號(hào)量來(lái)進(jìn)行同步和互斥操作,以保證數(shù)據(jù)的一致性和安全性。

消息隊(duì)列(Message Queue):消息隊(duì)列是一種通過(guò)隊(duì)列來(lái)實(shí)現(xiàn)進(jìn)程間通信的方式,發(fā)送進(jìn)程將消息放入隊(duì)列中,接收進(jìn)程從隊(duì)列中取出消息。消息隊(duì)列可以用于進(jìn)程之間的異步通信。

信號(hào)量(Semaphore):信號(hào)量是一種用于進(jìn)程同步和互斥的機(jī)制,它可以控制多個(gè)進(jìn)程對(duì)共享資源的訪問(wèn)。信號(hào)量通常用于共享內(nèi)存和消息隊(duì)列等進(jìn)程間通信方式中。
在不同主機(jī)之間,進(jìn)程間通信一般通過(guò)網(wǎng)絡(luò)實(shí)現(xiàn)。常用的進(jìn)程間通信方式包括:

套接字(Socket):套接字是一種通用的進(jìn)程間通信方式,它可以在不同主機(jī)之間進(jìn)行通信。套接字通常使用TCP或UDP協(xié)議來(lái)實(shí)現(xiàn)數(shù)據(jù)傳輸。

遠(yuǎn)程過(guò)程調(diào)用(RPC):RPC是一種通過(guò)網(wǎng)絡(luò)調(diào)用遠(yuǎn)程計(jì)算機(jī)上的程序的機(jī)制。它可以讓不同主機(jī)之間的進(jìn)程像調(diào)用本地程序一樣調(diào)用遠(yuǎn)程程序。

遠(yuǎn)程方法調(diào)用(RMI):RMI是一種Java語(yǔ)言特有的進(jìn)程間通信方式,它允許Java程序在不同主機(jī)之間進(jìn)行通信。

十一、匿名管道概述

匿名管道是由操作系統(tǒng)內(nèi)核創(chuàng)建的一種特殊文件,它沒(méi)有文件名和文件系統(tǒng)中的實(shí)體,只能在創(chuàng)建它的進(jìn)程和其子進(jìn)程之間使用。匿名管道有兩個(gè)文件描述符,一個(gè)用于讀取數(shù)據(jù),一個(gè)用于寫入數(shù)據(jù)。父進(jìn)程可以通過(guò)寫入數(shù)據(jù)到管道中,子進(jìn)程通過(guò)從管道中讀取數(shù)據(jù)來(lái)進(jìn)行通信。
半雙工通信:管道是一種半雙工的通信方式,即數(shù)據(jù)只能在一個(gè)方向上流動(dòng)。在具體實(shí)現(xiàn)中,管道會(huì)創(chuàng)建兩個(gè)文件描述符,一個(gè)用于讀取數(shù)據(jù),一個(gè)用于寫入數(shù)據(jù)。因此,進(jìn)程只能在其中一個(gè)描述符上進(jìn)行讀寫操作,不能同時(shí)進(jìn)行。

父子進(jìn)程通信:管道只能在具有父子關(guān)系的進(jìn)程之間使用。這是因?yàn)楣艿朗怯梢粋€(gè)進(jìn)程創(chuàng)建的,另一個(gè)進(jìn)程只能通過(guò)繼承文件描述符的方式來(lái)使用該管道。

數(shù)據(jù)傳輸有序:管道中的數(shù)據(jù)傳輸是有序的,即寫入管道中的數(shù)據(jù)會(huì)按照先后順序被讀取出來(lái)。在同一時(shí)刻,只有一個(gè)進(jìn)程可以對(duì)管道進(jìn)行讀寫操作,因此不會(huì)出現(xiàn)數(shù)據(jù)交錯(cuò)的情況。

數(shù)據(jù)傳輸有限制:管道有一個(gè)固定的緩沖區(qū)大小,當(dāng)緩沖區(qū)已滿時(shí),寫入進(jìn)程會(huì)被阻塞,直到有足夠的空間可用。同樣地,當(dāng)緩沖區(qū)為空時(shí),讀取進(jìn)程也會(huì)被阻塞,直到有數(shù)據(jù)可用。

匿名管道:在Linux中,管道分為匿名管道和命名管道兩種形式。匿名管道沒(méi)有文件名和文件系統(tǒng)中的實(shí)體,只能在創(chuàng)建它的進(jìn)程和其子進(jìn)程之間使用。
每個(gè)進(jìn)程都有自己的輸入流和輸出流,而管道就是一種將輸出流和輸入流連接在一起的方式。通過(guò)將進(jìn)程的輸入流和輸出流通過(guò)管道連接在一起,可以實(shí)現(xiàn)進(jìn)程間的通信。
緩沖區(qū):管道的緩沖區(qū)是一個(gè)環(huán)形緩沖區(qū),它由兩個(gè)指針front和rear來(lái)維護(hù)。當(dāng)向管道寫入數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)被先寫入緩沖區(qū)中,如果緩沖區(qū)已滿,則寫入操作會(huì)被阻塞,等待緩沖區(qū)中有足夠的空間可用。讀取進(jìn)程從管道中讀取數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)從緩沖區(qū)中讀取,如果緩沖區(qū)為空,則讀取操作會(huì)被阻塞,等待緩沖區(qū)中有數(shù)據(jù)可用。

文件描述符:管道的文件描述符是一個(gè)包含兩個(gè)整數(shù)的數(shù)組,其中一個(gè)整數(shù)用于讀取數(shù)據(jù),另一個(gè)整數(shù)用于寫入數(shù)據(jù)。當(dāng)進(jìn)程打開(kāi)管道時(shí),會(huì)返回一個(gè)文件描述符,該文件描述符可以用于讀取或?qū)懭牍艿乐械臄?shù)據(jù)。

管道的狀態(tài):管道的狀態(tài)包括一些基本的屬性,如緩沖區(qū)大小、讀取進(jìn)程數(shù)量、寫入進(jìn)程數(shù)量等。在Linux中,可以使用fstat()系統(tǒng)調(diào)用來(lái)獲取管道的狀態(tài)信息。

管道的鎖:由于管道是多個(gè)進(jìn)程共享的資源,因此需要使用鎖來(lái)保護(hù)管道的操作。在Linux中,可以使用互斥鎖和條件變量來(lái)保護(hù)管道的讀寫操作。

十二、父子進(jìn)程通過(guò)匿名管道通信

創(chuàng)建匿名管道:在Linux中,可以使用pipe()系統(tǒng)調(diào)用來(lái)創(chuàng)建匿名管道。pipe()系統(tǒng)調(diào)用會(huì)返回兩個(gè)文件描述符,一個(gè)用于讀取數(shù)據(jù),一個(gè)用于寫入數(shù)據(jù)。

創(chuàng)建子進(jìn)程:在父進(jìn)程中,可以使用fork()系統(tǒng)調(diào)用來(lái)創(chuàng)建一個(gè)新的子進(jìn)程。子進(jìn)程會(huì)繼承父進(jìn)程的文件描述符。

關(guān)閉不需要的文件描述符:在子進(jìn)程中,由于子進(jìn)程也繼承了父進(jìn)程的文件描述符,因此需要關(guān)閉不需要的文件描述符,即寫入文件描述符或讀取文件描述符。

進(jìn)行通信:在父進(jìn)程中,可以使用寫入文件描述符向管道中寫入數(shù)據(jù);在子進(jìn)程中,可以使用讀取文件描述符從管道中讀取數(shù)據(jù)。

關(guān)閉文件描述符:在進(jìn)程使用完文件描述符后,需要將其關(guān)閉,以釋放系統(tǒng)資源。

十三、匿名管道通信案例

1. 創(chuàng)建匿名管道:在操作系統(tǒng)中,創(chuàng)建一個(gè)匿名管道來(lái)連接兩個(gè)進(jìn)程。管道可以被看作是一種特殊的文件,其中一個(gè)進(jìn)程可以將數(shù)據(jù)寫入管道,另一個(gè)進(jìn)程則可以從管道中讀取數(shù)據(jù)。

2. 創(chuàng)建子進(jìn)程:通常,匿名管道是由一個(gè)父進(jìn)程和一個(gè)子進(jìn)程之間進(jìn)行通信。因此,父進(jìn)程將創(chuàng)建一個(gè)子進(jìn)程來(lái)與其通信。在創(chuàng)建子進(jìn)程時(shí),父進(jìn)程需要將管道文件描述符復(fù)制到子進(jìn)程的文件描述符中。

3. 進(jìn)程通信:在子進(jìn)程中,它可以通過(guò)管道的寫入端將數(shù)據(jù)寫入管道。父進(jìn)程可以從管道的讀取端讀取這些數(shù)據(jù)。同樣,父進(jìn)程也可以通過(guò)管道的寫入端將數(shù)據(jù)寫入管道,而子進(jìn)程可以從管道的讀取端讀取這些數(shù)據(jù)。

4. 關(guān)閉管道:當(dāng)進(jìn)程完成通信時(shí),它們都應(yīng)該關(guān)閉管道。在父進(jìn)程和子進(jìn)程中,當(dāng)讀取到管道尾部時(shí),也應(yīng)該關(guān)閉管道。

十四、管道的讀寫特點(diǎn)和管道設(shè)置為非阻塞

要將Linux管道設(shè)置為非阻塞,可以使用fcntl函數(shù)來(lái)完成。具體步驟如下:

1. 打開(kāi)需要設(shè)置為非阻塞的管道

2. 使用fcntl函數(shù)獲取管道的當(dāng)前標(biāo)志位,可以使用F_GETFL命令來(lái)實(shí)現(xiàn)

3. 將獲取到的標(biāo)志位與O_NONBLOCK位進(jìn)行或操作,以設(shè)置管道為非阻塞模式

4. 使用fcntl函數(shù)將設(shè)置后的標(biāo)志位設(shè)置回管道中,可以使用F_SETFL命令來(lái)實(shí)現(xiàn)

十五、有名管道介紹及使用

有名管道的創(chuàng)建和使用與匿名管道類似,但有一些重要的區(qū)別。以下是有名管道的一些特點(diǎn):

1. 有名管道是在文件系統(tǒng)中存在的文件,并且可以在多個(gè)進(jìn)程之間共享。

2. 有名管道可以用于不相關(guān)的進(jìn)程之間的通信,而匿名管道只能在父子進(jìn)程之間使用。

3. 有名管道的創(chuàng)建和刪除是由文件系統(tǒng)完成的,而匿名管道只是由進(jìn)程創(chuàng)建的一組文件描述符。

4. 有名管道可以用于實(shí)現(xiàn)進(jìn)程間的同步。
有名管道的創(chuàng)建和使用與匿名管道類似,但有一些重要的區(qū)別。以下是有名管道的一些特點(diǎn):

1. 有名管道是在文件系統(tǒng)中存在的文件,并且可以在多個(gè)進(jìn)程之間共享。

2. 有名管道可以用于不相關(guān)的進(jìn)程之間的通信,而匿名管道只能在父子進(jìn)程之間使用。

3. 有名管道的創(chuàng)建和刪除是由文件系統(tǒng)完成的,而匿名管道只是由進(jìn)程創(chuàng)建的一組文件描述符。

4. 有名管道可以用于實(shí)現(xiàn)進(jìn)程間的同步。

使用FIFO進(jìn)行進(jìn)程間通信時(shí),需要注意以下幾點(diǎn):

1. FIFO是一種阻塞式I/O,當(dāng)沒(méi)有數(shù)據(jù)可用時(shí),讀取和寫入FIFO的進(jìn)程都會(huì)阻塞。

2. 在寫入FIFO之前,必須有一個(gè)進(jìn)程打開(kāi)FIFO進(jìn)行寫入操作。同樣,在讀取FIFO之前,必須有一個(gè)進(jìn)程打開(kāi)FIFO進(jìn)行讀取操作。

3. FIFO通常是用于單向通信的(例如,從一個(gè)進(jìn)程讀取數(shù)據(jù),或?qū)?shù)據(jù)寫入另一個(gè)進(jìn)程)。如果需要進(jìn)行雙向通信,通常需要?jiǎng)?chuàng)建兩個(gè)FIFO,一個(gè)用于讀取,另一個(gè)用于寫入。

4. 當(dāng)不再需要FIFO時(shí),必須顯式地刪除它。這可以通過(guò)使用rm命令或unlink()系統(tǒng)調(diào)用來(lái)完成。

FIFO是一種非常有用的IPC機(jī)制,可用于在不同的進(jìn)程之間進(jìn)行通信。在Linux中,F(xiàn)IFO通常被用于實(shí)現(xiàn)多個(gè)進(jìn)程之間的協(xié)作和同步。

十六、有名管道實(shí)現(xiàn)簡(jiǎn)單版聊天功能

十七、內(nèi)存映射

內(nèi)存映射(Memory Mapping)是一種文件I/O操作,它允許將文件映射到進(jìn)程的地址空間中,使得進(jìn)程可以像訪問(wèn)內(nèi)存一樣訪問(wèn)文件的內(nèi)容。使用內(nèi)存映射,可以避免使用read和write等系統(tǒng)調(diào)用進(jìn)行繁瑣的I/O操作,從而提高文件I/O操作的效率。

在Linux中,內(nèi)存映射主要通過(guò)mmap()系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)。
mmap是一種將文件映射到內(nèi)存的方法,可以用于高效地讀取和寫入文件。以下是使用mmap時(shí)需要注意的幾點(diǎn):

內(nèi)存限制:mmap將文件映射到內(nèi)存中,因此需要注意內(nèi)存的使用量。如果文件很大,可能會(huì)導(dǎo)致內(nèi)存不足,從而導(dǎo)致系統(tǒng)性能下降或崩潰。

文件訪問(wèn)權(quán)限:使用mmap需要確保文件具有適當(dāng)?shù)脑L問(wèn)權(quán)限。如果文件不可讀或不可寫,將無(wú)法使用mmap。

內(nèi)存對(duì)齊:mmap將文件映射到內(nèi)存時(shí)需要進(jìn)行內(nèi)存對(duì)齊,通常情況下是按頁(yè)面大?。ㄍǔ?KB)進(jìn)行對(duì)齊。因此,在使用mmap時(shí)需要確保訪問(wèn)的內(nèi)存地址與文件偏移量是頁(yè)面對(duì)齊的。

文件修改:如果使用mmap進(jìn)行寫操作,需要注意對(duì)文件進(jìn)行同步操作,以確保數(shù)據(jù)已經(jīng)寫入磁盤。否則,如果系統(tǒng)崩潰或出現(xiàn)其他異常情況,可能會(huì)導(dǎo)致數(shù)據(jù)丟失或損壞。

跨平臺(tái)兼容性:在跨平臺(tái)使用mmap時(shí)需要注意不同操作系統(tǒng)的實(shí)現(xiàn)差異,例如內(nèi)存對(duì)齊方式和文件訪問(wèn)權(quán)限等。需要確保代碼能夠在不同的操作系統(tǒng)上正確運(yùn)行。

錯(cuò)誤處理:使用mmap時(shí)需要注意錯(cuò)誤處理,例如文件不存在、內(nèi)存映射失敗等情況。需要根據(jù)具體情況進(jìn)行適當(dāng)?shù)奶幚恚员苊獬绦虺霈F(xiàn)崩潰等問(wèn)題。
1.打開(kāi)源文件和目標(biāo)文件,使用open函數(shù)打開(kāi)文件并返回文件描述符。2.獲取源文件的大小,使用stat函數(shù)獲取文件的信息,并從中獲取文件的大小。3.使用mmap函數(shù)將源文件映射到內(nèi)存中,將目標(biāo)文件映射到內(nèi)存中,并將源文件的內(nèi)容復(fù)制到目標(biāo)文件中。4使用munmap函數(shù)釋放內(nèi)存映射,使用close函數(shù)關(guān)閉文件描述符

十八、信號(hào)概述

在Linux系統(tǒng)中,信號(hào)(Signal)是進(jìn)程間通信的一種方式,用于通知進(jìn)程發(fā)生了某些事件。信號(hào)是異步事件,即進(jìn)程無(wú)法預(yù)測(cè)何時(shí)會(huì)接收到信號(hào),因此需要在處理信號(hào)時(shí)保持謹(jǐn)慎。

信號(hào)的目的是在運(yùn)行中的進(jìn)程之間傳遞信息,例如通知進(jìn)程某個(gè)事件的發(fā)生,向進(jìn)程發(fā)送中斷請(qǐng)求等。Linux系統(tǒng)中定義了多種信號(hào),每個(gè)信號(hào)都有一個(gè)唯一的編號(hào)和特定的含義。例如,SIGINT信號(hào)表示中斷進(jìn)程,通常是由用戶在終端上按下Ctrl+C鍵發(fā)送的。

信號(hào)的特點(diǎn)如下:

異步事件:信號(hào)是異步事件,可以在任何時(shí)刻被發(fā)送和接收。進(jìn)程無(wú)法預(yù)測(cè)何時(shí)會(huì)接收到信號(hào),因此需要謹(jǐn)慎處理。

中斷處理:當(dāng)進(jìn)程接收到信號(hào)時(shí),操作系統(tǒng)中斷進(jìn)程的正常執(zhí)行流程,轉(zhuǎn)而執(zhí)行信號(hào)處理函數(shù)。信號(hào)處理函數(shù)通常是一段短小的代碼片段,用于處理特定的事件。

優(yōu)先級(jí):在Linux系統(tǒng)中,信號(hào)具有優(yōu)先級(jí)。當(dāng)多個(gè)信號(hào)同時(shí)發(fā)送給進(jìn)程時(shí),系統(tǒng)會(huì)根據(jù)信號(hào)的優(yōu)先級(jí)確定信號(hào)的處理順序。

可靠性:信號(hào)的發(fā)送和接收都是可靠的。如果進(jìn)程向其他進(jìn)程發(fā)送信號(hào),系統(tǒng)會(huì)保證信號(hào)被傳遞到目標(biāo)進(jìn)程。如果進(jìn)程接收到一個(gè)信號(hào),系統(tǒng)會(huì)保證該信號(hào)不會(huì)丟失。
以下是Linux系統(tǒng)中常見(jiàn)的信號(hào)列表及其含義:

SIGHUP:掛起信號(hào),通常在終端會(huì)話結(jié)束時(shí)發(fā)送給進(jìn)程。

SIGINT:中斷信號(hào),通常由用戶在終端上按下Ctrl+C鍵發(fā)送給進(jìn)程。

SIGQUIT:退出信號(hào),通常由用戶在終端上按下Ctrl+\鍵發(fā)送給進(jìn)程。

SIGILL:非法指令信號(hào),通常表示進(jìn)程執(zhí)行了不合法的指令或操作。

SIGABRT:終止信號(hào),通常由程序自身調(diào)用abort函數(shù)發(fā)送給自己,表示程序出現(xiàn)了致命錯(cuò)誤。

SIGFPE:浮點(diǎn)異常信號(hào),通常表示進(jìn)程執(zhí)行了一條非法的浮點(diǎn)運(yùn)算指令。

SIGKILL:殺死信號(hào),可以立即終止進(jìn)程的運(yùn)行,無(wú)法被忽略或捕獲。

SIGSEGV:段錯(cuò)誤信號(hào),通常表示進(jìn)程試圖訪問(wèn)未分配或不允許訪問(wèn)的內(nèi)存地址。

SIGPIPE:管道破裂信號(hào),通常表示進(jìn)程試圖向已關(guān)閉的管道寫入數(shù)據(jù)。

SIGALRM:鬧鐘信號(hào),通常用于實(shí)現(xiàn)定時(shí)器功能。

SIGTERM:終止信號(hào),可以請(qǐng)求進(jìn)程正常退出,并允許進(jìn)程進(jìn)行清理操作。

SIGUSR1/SIGUSR2:用戶定義信號(hào),通常由進(jìn)程自定義使用。

SIGCHLD:子進(jìn)程狀態(tài)改變信號(hào),通常由父進(jìn)程接收,用于通知父進(jìn)程子進(jìn)程的狀態(tài)改變。

SIGCONT:繼續(xù)信號(hào),通常用于繼續(xù)之前被暫停的進(jìn)程。

SIGSTOP:停止信號(hào),可以暫停進(jìn)程的運(yùn)行,無(wú)法被忽略或捕獲。

SIGTSTP:掛起信號(hào),通常由用戶在終端上按下Ctrl+Z鍵發(fā)送給進(jìn)程,用于將進(jìn)程暫停并放入后臺(tái)。

Term(終止,默認(rèn)處理動(dòng)作):當(dāng)進(jìn)程接收到該信號(hào)時(shí),進(jìn)程會(huì)立即退出并終止運(yùn)行。

Ign(忽略):當(dāng)進(jìn)程接收到該信號(hào)時(shí),進(jìn)程會(huì)直接忽略該信號(hào),繼續(xù)執(zhí)行。

Core(生成核心轉(zhuǎn)儲(chǔ)文件):當(dāng)進(jìn)程接收到該信號(hào)時(shí),進(jìn)程會(huì)生成一個(gè)核心轉(zhuǎn)儲(chǔ)文件,用于調(diào)試和分析程序錯(cuò)誤。

Stop(停止進(jìn)程,默認(rèn)處理動(dòng)作):當(dāng)進(jìn)程接收到該信號(hào)時(shí),進(jìn)程會(huì)被暫停,并等待被其他進(jìn)程繼續(xù)執(zhí)行。

Cont(繼續(xù)進(jìn)程):當(dāng)進(jìn)程接收到該信號(hào)時(shí),進(jìn)程會(huì)從之前被暫停的地方繼續(xù)執(zhí)行。


十九、kill、raise、abort函數(shù)

kill函數(shù):可以向指定的進(jìn)程或進(jìn)程組發(fā)送信號(hào)。其函數(shù)原型為int kill(pid_t pid, int sig);其中,pid參數(shù)指定要發(fā)送信號(hào)的進(jìn)程或進(jìn)程組的ID,sig參數(shù)指定要發(fā)送的信號(hào)編號(hào)。raise函數(shù):可以向當(dāng)前進(jìn)程發(fā)送信號(hào)。其函數(shù)原型為:int raise(int sig);其中,sig參數(shù)指定要發(fā)送的信號(hào)編號(hào)。abort函數(shù):可以向當(dāng)前進(jìn)程發(fā)送SIGABRT信號(hào),使其自行終止。其函數(shù)原型為:void abort(void)。需要注意的是,使用kill、raise和abort函數(shù)向進(jìn)程發(fā)送信號(hào)時(shí),需要注意信號(hào)的含義和作用,避免信號(hào)的誤用導(dǎo)致不必要的麻煩或錯(cuò)誤。同時(shí),對(duì)于一些特殊的信號(hào),例如SIGKILL和SIGSTOP,無(wú)法被忽略或捕獲,因此需要謹(jǐn)慎使用。

二十、alarm函數(shù)

在Linux系統(tǒng)中,可以使用alarm函數(shù)來(lái)設(shè)置定時(shí)器,用于在指定的時(shí)間間隔后向當(dāng)前進(jìn)程發(fā)送SIGALRM信號(hào)。其函數(shù)原型為:unsigned int alarm(unsigned int seconds);其中,seconds參數(shù)指定定時(shí)器的時(shí)間間隔,單位為秒。當(dāng)定時(shí)器到達(dá)指定時(shí)間間隔時(shí),操作系統(tǒng)會(huì)向當(dāng)前進(jìn)程發(fā)送SIGALRM信號(hào),可以通過(guò)信號(hào)處理函數(shù)來(lái)處理該信號(hào)。需要注意的是,使用alarm函數(shù)設(shè)置定時(shí)器時(shí),如果之前已經(jīng)設(shè)置過(guò)定時(shí)器,則之前的定時(shí)器會(huì)被覆蓋。而且,如果在定時(shí)器到達(dá)之前調(diào)用了alarm函數(shù),則會(huì)取消之前的定時(shí)器。因此,在使用alarm函數(shù)時(shí)需要謹(jǐn)慎操作,確保定時(shí)器的設(shè)置和取消符合預(yù)期。

二十一、setitimer定時(shí)器函數(shù)

在Linux系統(tǒng)中,可以使用setitimer函數(shù)來(lái)設(shè)置定時(shí)器,用于在指定的時(shí)間間隔后向當(dāng)前進(jìn)程發(fā)送SIGALRM信號(hào)。相對(duì)于alarm函數(shù),setitimer函數(shù)提供了更加靈活的定時(shí)器設(shè)置方式,可以設(shè)置定時(shí)器的初始時(shí)間、周期時(shí)間和到期時(shí)間,并支持多種定時(shí)器類型。其函數(shù)原型為:int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);其中,which參數(shù)指定要使用的定時(shí)器類型,可以是以下三個(gè)值之一:

ITIMER_REAL:使用系統(tǒng)的實(shí)時(shí)時(shí)鐘來(lái)計(jì)時(shí),定時(shí)器到期時(shí)發(fā)送SIGALRM信號(hào)。

ITIMER_VIRTUAL:使用進(jìn)程的虛擬時(shí)鐘來(lái)計(jì)時(shí),定時(shí)器到期時(shí)發(fā)送SIGVTALRM信號(hào)。

ITIMER_PROF:使用進(jìn)程和系統(tǒng)的時(shí)間來(lái)計(jì)時(shí),定時(shí)器到期時(shí)發(fā)送SIGPROF信號(hào)。

new_value參數(shù)是一個(gè)指向結(jié)構(gòu)體itimerval的指針,用于設(shè)置新的定時(shí)器值。該結(jié)構(gòu)體包含了兩個(gè)成員:

it_interval:定時(shí)器的周期時(shí)間,即定時(shí)器到期后再次觸發(fā)的時(shí)間間隔。

it_value:定時(shí)器的初始時(shí)間,即定時(shí)器第一次到期的時(shí)間間隔。當(dāng)定時(shí)器到達(dá)指定時(shí)間間隔時(shí),操作系統(tǒng)會(huì)向當(dāng)前進(jìn)程發(fā)送相應(yīng)的信號(hào),可以通過(guò)信號(hào)處理函數(shù)來(lái)處理該信號(hào)。需要注意的是,使用setitimer函數(shù)設(shè)置定時(shí)器時(shí),需要確保定時(shí)器的設(shè)置和取消符合預(yù)期,避免產(chǎn)生不必要的麻煩或錯(cuò)誤。同時(shí),對(duì)于一些特殊的信號(hào),例如SIGKILL和SIGSTOP,無(wú)法被忽略或捕獲,因此需要謹(jǐn)慎使用。

二十二、signal信號(hào)捕捉函數(shù)

在Linux系統(tǒng)中,可以使用signal函數(shù)來(lái)捕捉進(jìn)程接收到的信號(hào),并指定相應(yīng)的信號(hào)處理函數(shù)。其函數(shù)原型為:void (*signal(int signum, void (*handler)(int)))(int);其中,signum參數(shù)指定要捕捉的信號(hào)編號(hào),handler參數(shù)指定要安裝的信號(hào)處理函數(shù)。該函數(shù)返回值為指向原信號(hào)處理函數(shù)的指針.需要注意的是,signal函數(shù)只能安裝一次信號(hào)處理函數(shù)。如果要更改信號(hào)處理函數(shù),可以再次調(diào)用signal函數(shù)進(jìn)行安裝。同時(shí),對(duì)于一些特殊的信號(hào),例如SIGKILL和SIGSTOP,無(wú)法被忽略或捕獲,因此無(wú)法通過(guò)signal函數(shù)來(lái)安裝信號(hào)處理函數(shù)。

另外,為了避免信號(hào)處理函數(shù)與其他代碼產(chǎn)生競(jìng)爭(zhēng)條件,通常建議在信號(hào)處理函數(shù)中盡量避免使用不可重入的函數(shù),例如printf和malloc等。如果必須使用這些函數(shù),可以使用異步信號(hào)安全函數(shù)(async-signal-safe function)來(lái)代替。異步信號(hào)安全函數(shù)是指可以在信號(hào)處理函數(shù)中安全使用的函數(shù),它們不會(huì)產(chǎn)生競(jìng)爭(zhēng)條件,也不會(huì)因?yàn)橹袛喽鴮?dǎo)致不確定的行為。常見(jiàn)的異步信號(hào)安全函數(shù)包括write、_exit、read、fcntl等。

二十三、信號(hào)集及相關(guān)函數(shù)

在Linux系統(tǒng)中,可以使用信號(hào)集(signal set)來(lái)表示一組信號(hào),用于對(duì)多個(gè)信號(hào)進(jìn)行管理和操作。信號(hào)集是一個(gè)整數(shù)數(shù)組,每個(gè)數(shù)組元素表示一個(gè)信號(hào),對(duì)應(yīng)位置的值為1表示該信號(hào)被包含在信號(hào)集中,為0表示不包含在信號(hào)集中。

可以使用以下函數(shù)來(lái)操作信號(hào)集:
sigemptyset函數(shù):用于清空信號(hào)集,將所有信號(hào)從信號(hào)集中移除。sigfillset函數(shù):用于將所有信號(hào)加入信號(hào)集中。sigaddset函數(shù):用于將指定的信號(hào)加入信號(hào)集中。sigdelset函數(shù):用于將指定的信號(hào)從信號(hào)集中移除。sigismember函數(shù):用于判斷指定的信號(hào)是否包含在信號(hào)集中。
在Linux系統(tǒng)中,每個(gè)進(jìn)程都有兩個(gè)與信號(hào)相關(guān)的集合:

阻塞信號(hào)集(Blocked signal set):用于管理當(dāng)前被阻塞的信號(hào)。當(dāng)進(jìn)程接收到一個(gè)被阻塞的信號(hào)時(shí),該信號(hào)不會(huì)被處理,而是被加入到阻塞信號(hào)集中,直到該信號(hào)被解除阻塞后才會(huì)被處理??梢允褂胹igprocmask函數(shù)來(lái)設(shè)置和獲取阻塞信號(hào)集。

未決信號(hào)集(Pending signal set):用于管理當(dāng)前未被處理的信號(hào)。當(dāng)進(jìn)程接收到一個(gè)信號(hào)時(shí),該信號(hào)會(huì)被加入到未決信號(hào)集中,直到該信號(hào)被處理后才會(huì)從未決信號(hào)集中刪除??梢允褂胹igpending函數(shù)來(lái)獲取當(dāng)前未決信號(hào)集中的信號(hào)。

可以使用以下函數(shù)來(lái)操作阻塞信號(hào)集:

sigprocmask函數(shù):用于設(shè)置和獲取阻塞信號(hào)集。int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
```

其中,how參數(shù)指定操作類型,可以是以下三個(gè)值之一:

- SIG_BLOCK:將set指定的信號(hào)集中的信號(hào)添加到當(dāng)前進(jìn)程的阻塞信號(hào)集中。

- SIG_UNBLOCK:將set指定的信號(hào)集中的信號(hào)從當(dāng)前進(jìn)程的阻塞信號(hào)集中移除。

- SIG_SETMASK:用set指定的信號(hào)集替換當(dāng)前進(jìn)程的阻塞信號(hào)集。

set參數(shù)為指向要設(shè)置的信號(hào)集的指針,oldset參數(shù)為指向用于存儲(chǔ)原阻塞信號(hào)集的指針。如果oldset參數(shù)不為NULL,則會(huì)將原阻塞信號(hào)集存儲(chǔ)到該指針指向的位置中。sigpending函數(shù):用于獲取當(dāng)前未決信號(hào)集中的信號(hào)。

#include <signal.h>

int sigpending(sigset_t *set);

其中,set參數(shù)為指向要存儲(chǔ)未決信號(hào)集的指針。該函數(shù)將當(dāng)前未決信號(hào)集存儲(chǔ)到set指向的位置中。
需要注意的是,阻塞信號(hào)集和未決信號(hào)集可以用于控制信號(hào)的處理方式,但在使用時(shí)需要特別小心,以免導(dǎo)致信號(hào)丟失或不被處理。此外,對(duì)于一些特殊的信號(hào),例如SIGKILL和SIGSTOP,無(wú)法被阻塞或捕獲。
sigemptyset函數(shù):用于清空信號(hào)集,將所有信號(hào)從信號(hào)集中移除。sigfillset函數(shù):用于將所有信號(hào)加入信號(hào)集中。sigaddset函數(shù):用于將指定的信號(hào)加入信號(hào)集中。sigdelset函數(shù):用于將指定的信號(hào)從信號(hào)集中移除。sigismember函數(shù):用于判斷指定的信號(hào)是否包含在信號(hào)集中。sigprocmask函數(shù):用于設(shè)置和獲取阻塞信號(hào)集。sigpending函數(shù):用于獲取當(dāng)前未決信號(hào)集中的信號(hào)。

二十四、sigprocmask 函數(shù)使用

在Linux系統(tǒng)中,sigprocmask函數(shù)用于設(shè)置和獲取進(jìn)程的阻塞信號(hào)集??梢允褂迷摵瘮?shù)來(lái)控制進(jìn)程是否接收特定的信號(hào)。

sigprocmask函數(shù)的原型如下:int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);其中,how參數(shù)指定操作類型,可以是以下三個(gè)值之一:

SIG_BLOCK:將set指定的信號(hào)集中的信號(hào)添加到當(dāng)前進(jìn)程的阻塞信號(hào)集中。
SIG_UNBLOCK:將set指定的信號(hào)集中的信號(hào)從當(dāng)前進(jìn)程的阻塞信號(hào)集中移除。
SIG_SETMASK:用set指定的信號(hào)集替換當(dāng)前進(jìn)程的阻塞信號(hào)集。
set參數(shù)為指向要設(shè)置的信號(hào)集的指針,oldset參數(shù)為指向用于存儲(chǔ)原阻塞信號(hào)集的指針。如果oldset參數(shù)不為NULL,則會(huì)將原阻塞信號(hào)集存儲(chǔ)到該指針指向的位置中。需要注意的是,阻塞信號(hào)集是對(duì)當(dāng)前進(jìn)程全局生效的,因此需要謹(jǐn)慎使用,避免對(duì)整個(gè)進(jìn)程的信號(hào)處理產(chǎn)生不良影響。同時(shí),在阻塞信號(hào)集中阻塞某個(gè)信號(hào)時(shí),該信號(hào)不會(huì)被丟棄,而是會(huì)被緩存起來(lái),直到解除阻塞后再被處理。因此,如果在某個(gè)時(shí)刻多個(gè)信號(hào)被阻塞,這些信號(hào)都將被緩存起來(lái),可能會(huì)導(dǎo)致后續(xù)處理時(shí)出現(xiàn)延遲。

二十五、sigaction 信號(hào)捕捉函數(shù)

在Linux系統(tǒng)中,可以使用sigaction函數(shù)來(lái)設(shè)置信號(hào)的處理方式,即捕捉信號(hào)。該函數(shù)可以指定信號(hào)的處理函數(shù),以及在信號(hào)處理函數(shù)中需要屏蔽的信號(hào)。

sigaction函數(shù)的原型如下:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);其中,signum參數(shù)為要設(shè)置的信號(hào)編號(hào),act參數(shù)為指向要設(shè)置的信號(hào)處理方式的結(jié)構(gòu)體指針,oldact參數(shù)為指向用于存儲(chǔ)原信號(hào)處理方式的結(jié)構(gòu)體指針。如果oldact參數(shù)不為NULL,則會(huì)將原信號(hào)處理方式存儲(chǔ)到該指針指向的位置中。需要注意的是,信號(hào)處理函數(shù)應(yīng)該盡可能的簡(jiǎn)潔和快速,避免在信號(hào)處理函數(shù)中執(zhí)行復(fù)雜的操作。同時(shí),在信號(hào)處理函數(shù)中只能調(diào)用一些異步信號(hào)安全的函數(shù),不能調(diào)用一些可能會(huì)阻塞的函數(shù),否則可能會(huì)引起不可預(yù)知的問(wèn)題。
1.信號(hào)到達(dá)進(jìn)程。當(dāng)進(jìn)程接收到信號(hào)時(shí),內(nèi)核會(huì)將信號(hào)所屬的進(jìn)程標(biāo)識(shí)符和信號(hào)編號(hào)記錄在內(nèi)核數(shù)據(jù)結(jié)構(gòu)中,并將進(jìn)程標(biāo)識(shí)符加入到等待該信號(hào)的進(jìn)程隊(duì)列中。

2.內(nèi)核檢查進(jìn)程的信號(hào)屏蔽字。在將信號(hào)發(fā)送給進(jìn)程之前,內(nèi)核會(huì)檢查進(jìn)程的信號(hào)屏蔽字,如果該信號(hào)在屏蔽字中,則該信號(hào)將被屏蔽,并不會(huì)發(fā)送給進(jìn)程。否則,內(nèi)核將繼續(xù)發(fā)送信號(hào)。

3.內(nèi)核發(fā)送信號(hào)給進(jìn)程。如果信號(hào)沒(méi)有被屏蔽,則內(nèi)核會(huì)將信號(hào)發(fā)送給進(jìn)程。在發(fā)送信號(hào)之前,內(nèi)核會(huì)暫停進(jìn)程的執(zhí)行,并將進(jìn)程的上下文保存到內(nèi)核數(shù)據(jù)結(jié)構(gòu)中,以便在信號(hào)處理函數(shù)執(zhí)行完畢后恢復(fù)進(jìn)程的執(zhí)行。

4.內(nèi)核執(zhí)行信號(hào)處理函數(shù)。當(dāng)進(jìn)程接收到信號(hào)時(shí),內(nèi)核會(huì)執(zhí)行該進(jìn)程的信號(hào)處理函數(shù)。內(nèi)核會(huì)先檢查信號(hào)處理函數(shù)是否存在,如果存在,則將進(jìn)程的上下文切換到信號(hào)處理函數(shù)中執(zhí)行。在執(zhí)行信號(hào)處理函數(shù)期間,內(nèi)核會(huì)將進(jìn)程的信號(hào)屏蔽字設(shè)置為信號(hào)處理函數(shù)中指定的信號(hào)屏蔽字,以避免其他信號(hào)的干擾。如果信號(hào)處理函數(shù)執(zhí)行完畢,則將進(jìn)程的上下文恢復(fù),并繼續(xù)執(zhí)行進(jìn)程。

二十六、SIGCHLD 信號(hào)

在Linux系統(tǒng)中,當(dāng)一個(gè)進(jìn)程的子進(jìn)程終止或停止時(shí),內(nèi)核會(huì)向父進(jìn)程發(fā)送SIGCHLD信號(hào)。該信號(hào)用于告知父進(jìn)程子進(jìn)程的狀態(tài)改變,父進(jìn)程可以通過(guò)捕捉該信號(hào)來(lái)獲取子進(jìn)程的狀態(tài)。

SIGCHLD信號(hào)的默認(rèn)處理方式是忽略該信號(hào)。因此,如果父進(jìn)程不捕捉該信號(hào),當(dāng)子進(jìn)程終止或停止時(shí),該信號(hào)不會(huì)對(duì)父進(jìn)程產(chǎn)生任何影響。

可以使用sigaction函數(shù)捕捉SIGCHLD信號(hào),并在信號(hào)處理函數(shù)中處理子進(jìn)程的狀態(tài)。當(dāng)捕捉到SIGCHLD信號(hào)時(shí),父進(jìn)程可以調(diào)用waitpid函數(shù)等待子進(jìn)程狀態(tài)的改變,以獲取子進(jìn)程的退出狀態(tài)碼和其他信息。需要注意的是,當(dāng)一個(gè)進(jìn)程的子進(jìn)程終止或停止時(shí),內(nèi)核只會(huì)向其父進(jìn)程發(fā)送一次SIGCHLD信號(hào),即使有多個(gè)子進(jìn)程同時(shí)終止或停止。因此,在SIGCHLD信號(hào)處理函數(shù)中,需要使用循環(huán)調(diào)用waitpid函數(shù)來(lái)處理所有的子進(jìn)程狀態(tài)。另外,由于SIGCHLD信號(hào)是異步發(fā)生的,因此在信號(hào)處理函數(shù)中需要注意使用異步信號(hào)安全的函數(shù),避免出現(xiàn)競(jìng)態(tài)條件等問(wèn)題。

二十七、共享內(nèi)存

Linux的共享內(nèi)存具有以下優(yōu)勢(shì):

高性能:共享內(nèi)存的訪問(wèn)速度比其他進(jìn)程間通信方式(如管道、消息隊(duì)列等)更快,因?yàn)楣蚕韮?nèi)存避免了數(shù)據(jù)的復(fù)制和系統(tǒng)調(diào)用的開(kāi)銷。

靈活性:共享內(nèi)存可以在不同進(jìn)程之間共享大量數(shù)據(jù),不僅可以用于進(jìn)程間通信,還可以用于在同一進(jìn)程的不同線程之間共享數(shù)據(jù)。

易用性:使用共享內(nèi)存的方式簡(jiǎn)單,只需要?jiǎng)?chuàng)建共享內(nèi)存區(qū)域、連接到共享內(nèi)存區(qū)域并訪問(wèn)共享內(nèi)存區(qū)域即可。

可擴(kuò)展性:共享內(nèi)存可以動(dòng)態(tài)地增加或減少內(nèi)存大小,使得應(yīng)用程序可以根據(jù)需要調(diào)整內(nèi)存大小。

穩(wěn)定性:共享內(nèi)存是在內(nèi)存中分配的,不像文件或管道等通信方式會(huì)受到硬盤容量或磁盤速度等因素的影響。因此,共享內(nèi)存通常更加穩(wěn)定和可靠。
共享內(nèi)存的使用需要以下步驟:

創(chuàng)建共享內(nèi)存區(qū)域。可以使用shmget系統(tǒng)調(diào)用創(chuàng)建一個(gè)共享內(nèi)存區(qū)域,該調(diào)用會(huì)返回一個(gè)共享內(nèi)存標(biāo)識(shí)符。需要指定創(chuàng)建的共享內(nèi)存大小、權(quán)限等參數(shù)。

連接到共享內(nèi)存區(qū)域??梢允褂胹hmat系統(tǒng)調(diào)用將進(jìn)程連接到共享內(nèi)存區(qū)域,該調(diào)用會(huì)返回共享內(nèi)存區(qū)域的起始地址。需要指定共享內(nèi)存標(biāo)識(shí)符和連接方式等參數(shù)。

使用共享內(nèi)存。連接到共享內(nèi)存區(qū)域后,可以像訪問(wèn)普通內(nèi)存一樣訪問(wèn)共享內(nèi)存區(qū)域。多個(gè)進(jìn)程可以共享同一塊內(nèi)存區(qū)域,可以通過(guò)在內(nèi)存中存儲(chǔ)數(shù)據(jù)來(lái)進(jìn)行進(jìn)程間通信。

分離共享內(nèi)存區(qū)域??梢允褂胹hmdt系統(tǒng)調(diào)用將進(jìn)程與共享內(nèi)存區(qū)域分離,該調(diào)用會(huì)釋放進(jìn)程與共享內(nèi)存區(qū)域的連接。需要指定共享內(nèi)存區(qū)域的起始地址。

刪除共享內(nèi)存區(qū)域??梢允褂胹hmctl系統(tǒng)調(diào)用刪除共享內(nèi)存區(qū)域,該調(diào)用會(huì)釋放共享內(nèi)存區(qū)域并撤銷與該區(qū)域的所有連接。需要指定共享內(nèi)存標(biāo)識(shí)符和刪除方式等參數(shù)。
ipcs是Linux系統(tǒng)中的一個(gè)命令,用于顯示當(dāng)前系統(tǒng)中的IPC資源,包括消息隊(duì)列、共享內(nèi)存和信號(hào)量等。ipcs命令的使用方法如下:-a:顯示所有IPC資源的信息;
-m:顯示共享內(nèi)存的信息;
-q:顯示消息隊(duì)列的信息;
-s:顯示信號(hào)量的信息。ipcrm是Linux系統(tǒng)中的一個(gè)命令,用于刪除IPC資源,包括消息隊(duì)列、共享內(nèi)存和信號(hào)量等。ipcrm命令的使用方法如下:-m:刪除共享內(nèi)存;
-q:刪除消息隊(duì)列;
-s:刪除信號(hào)量。

二十八、進(jìn)程組、會(huì)話、進(jìn)程終端

在Linux系統(tǒng)中,終端是用戶與操作系統(tǒng)進(jìn)行交互的一個(gè)重要界面,也是用戶使用Linux系統(tǒng)的主要方式之一。終端可以分為物理終端和虛擬終端兩種形式。

物理終端:物理終端是指通過(guò)連接計(jì)算機(jī)的串口、并口、繪圖儀和控制臺(tái)等物理設(shè)備來(lái)提供終端功能,用戶通過(guò)這些設(shè)備與計(jì)算機(jī)進(jìn)行交互。在現(xiàn)代計(jì)算機(jī)中,物理終端已經(jīng)較少使用。

虛擬終端:虛擬終端是指通過(guò)軟件模擬的終端,提供與物理終端相同的終端功能。在Linux系統(tǒng)中,可以通過(guò)多個(gè)虛擬終端同時(shí)進(jìn)行工作,每個(gè)虛擬終端都有自己的命令行提示符和命令執(zhí)行環(huán)境,用戶可以在不同的虛擬終端中運(yùn)行不同的程序和命令。

在Linux系統(tǒng)中,可以使用以下命令來(lái)管理終端:

tty命令:用于顯示當(dāng)前終端的名稱。

who命令:用于顯示當(dāng)前登錄到系統(tǒng)的用戶信息,包括用戶名、登錄時(shí)間、登錄終端等。

login命令:用于登錄到系統(tǒng),需要輸入正確的用戶名和密碼。

logout或exit命令:用于退出當(dāng)前登錄的終端。

Ctrl+Alt+F1F6鍵:用于切換不同的虛擬終端,F(xiàn)1F6鍵分別對(duì)應(yīng)不同的虛擬終端。

reset命令:用于清屏并重置終端。

stty命令:用于設(shè)置終端屬性,如終端大小、回顯方式、流控制等。
在Linux系統(tǒng)中,可以使用以下命令來(lái)管理進(jìn)程組:

ps命令:用于顯示當(dāng)前系統(tǒng)中的進(jìn)程信息,可以使用ps命令查看每個(gè)進(jìn)程的進(jìn)程ID(PID)和進(jìn)程組ID(PGID)等信息。

jobs命令:用于顯示當(dāng)前作業(yè)的狀態(tài),包括作業(yè)號(hào)、進(jìn)程ID、作業(yè)狀態(tài)等。

fg命令:用于將一個(gè)后臺(tái)作業(yè)移動(dòng)到前臺(tái)運(yùn)行。

bg命令:用于將一個(gè)前臺(tái)作業(yè)移動(dòng)到后臺(tái)運(yùn)行。

kill命令:用于向一個(gè)或多個(gè)進(jìn)程發(fā)送信號(hào),可以使用kill命令向進(jìn)程組發(fā)送信號(hào)。

setpgid函數(shù):用于設(shè)置進(jìn)程的進(jìn)程組ID。

getpgid函數(shù):用于獲取進(jìn)程的進(jìn)程組ID。
在Linux系統(tǒng)中,會(huì)話是一組相互關(guān)聯(lián)的進(jìn)程的集合,這些進(jìn)程共享同一個(gè)控制終端。會(huì)話通常由一個(gè)shell進(jìn)程創(chuàng)建,并且在shell進(jìn)程退出時(shí)結(jié)束。

會(huì)話的主要作用是為了將一組相互關(guān)聯(lián)的進(jìn)程組織在一起,使它們能夠共享同一個(gè)控制終端,并且可以進(jìn)行作業(yè)控制和進(jìn)程組間通信等操作。

在Linux系統(tǒng)中,可以使用以下命令來(lái)管理會(huì)話:

login命令:用于登錄到系統(tǒng),并創(chuàng)建一個(gè)新的會(huì)話。

tty命令:用于顯示當(dāng)前終端的名稱,也可以用于查看當(dāng)前會(huì)話的名稱。

ps命令:用于顯示當(dāng)前系統(tǒng)中的進(jìn)程信息,可以使用ps命令查看每個(gè)進(jìn)程的會(huì)話ID(SID)等信息。

setsid命令:用于創(chuàng)建一個(gè)新的會(huì)話。

nohup命令:用于在后臺(tái)運(yùn)行一個(gè)進(jìn)程,并且不受終端關(guān)閉等影響。

需要注意的是,在使用會(huì)話時(shí)需要謹(jǐn)慎操作,避免誤操作導(dǎo)致系統(tǒng)數(shù)據(jù)丟失或系統(tǒng)崩潰等問(wèn)題。在進(jìn)行敏感操作時(shí),建議使用root用戶或具有足夠權(quán)限的用戶進(jìn)行操作。
進(jìn)程組、會(huì)話和控制終端之間的關(guān)系可以總結(jié)如下:

一個(gè)進(jìn)程可以屬于一個(gè)進(jìn)程組,一個(gè)進(jìn)程組可以有多個(gè)進(jìn)程。

一個(gè)進(jìn)程組可以屬于一個(gè)會(huì)話,一個(gè)會(huì)話可以有多個(gè)進(jìn)程組。

一個(gè)會(huì)話與一個(gè)控制終端相互關(guān)聯(lián),一個(gè)控制終端可以與多個(gè)會(huì)話關(guān)聯(lián)。

一個(gè)會(huì)話中的第一個(gè)進(jìn)程被稱為控制進(jìn)程,控制進(jìn)程與控制終端相互關(guān)聯(lián)。

控制進(jìn)程可以通過(guò)控制終端與用戶進(jìn)行交互,同時(shí)可以對(duì)進(jìn)程組進(jìn)行作業(yè)控制和進(jìn)程組間通信等操作。
在Linux系統(tǒng)中,有一些函數(shù)可以用于進(jìn)行進(jìn)程組、會(huì)話操作,下面是一些常用的函數(shù):

setpgid(pid, pgid):將進(jìn)程pid加入進(jìn)程組pgid中,如果pgid為0,則將pid所在的進(jìn)程組ID設(shè)置為pid本身的進(jìn)程ID。

getpgid(pid):獲取進(jìn)程pid所在的進(jìn)程組ID。

setsid():創(chuàng)建一個(gè)新的會(huì)話,并使調(diào)用進(jìn)程成為該會(huì)話的首進(jìn)程和進(jìn)程組組長(zhǎng)。

getpgrp():獲取當(dāng)前進(jìn)程所在的進(jìn)程組ID。

tcgetpgrp(fd):獲取與文件描述符fd關(guān)聯(lián)的終端的進(jìn)程組ID。

tcsetpgrp(fd, pgrp):將與文件描述符fd關(guān)聯(lián)的終端的進(jìn)程組ID設(shè)置為pgrp。

需要注意的是,這些函數(shù)需要在合適的上下文中使用,否則可能會(huì)導(dǎo)致意想不到的結(jié)果或者錯(cuò)誤。例如,在使用setsid函數(shù)創(chuàng)建一個(gè)新的會(huì)話之前,需要先關(guān)閉所有的文件描述符,否則會(huì)話可能會(huì)繼承該進(jìn)程打開(kāi)的文件描述符,導(dǎo)致意想不到的結(jié)果。

另外,Linux系統(tǒng)也提供了一些命令來(lái)進(jìn)行進(jìn)程組、會(huì)話操作,例如:

jobs:查看當(dāng)前shell會(huì)話中的作業(yè)信息。

fg:將一個(gè)后臺(tái)作業(yè)移動(dòng)到前臺(tái)運(yùn)行。

bg:將一個(gè)前臺(tái)作業(yè)移動(dòng)到后臺(tái)運(yùn)行。

kill:向一個(gè)或多個(gè)進(jìn)程發(fā)送信號(hào),可以使用kill命令向進(jìn)程組發(fā)送信號(hào)。

二十九、守護(hù)進(jìn)程

在Linux系統(tǒng)中,守護(hù)進(jìn)程(Daemon)是一種在后臺(tái)運(yùn)行的進(jìn)程,它通常沒(méi)有控制終端,而是以系統(tǒng)服務(wù)的形式運(yùn)行,為系統(tǒng)提供一些常駐服務(wù)(如網(wǎng)絡(luò)服務(wù)、打印服務(wù)等)。

守護(hù)進(jìn)程通常在系統(tǒng)啟動(dòng)時(shí)自動(dòng)啟動(dòng),以root用戶身份運(yùn)行,并且在運(yùn)行過(guò)程中不受用戶登錄和注銷的影響。它們通常不會(huì)向控制臺(tái)輸出信息,而是將日志信息寫入日志文件中。
創(chuàng)建守護(hù)進(jìn)程的步驟:

創(chuàng)建一個(gè)新的進(jìn)程,然后通過(guò)調(diào)用setsid函數(shù)創(chuàng)建一個(gè)新的會(huì)話,并使該進(jìn)程成為會(huì)話的首進(jìn)程。

將該進(jìn)程的umask設(shè)置為0,以便它可以創(chuàng)建任何文件和目錄。

關(guān)閉所有的文件描述符,以避免它們繼承自父進(jìn)程。

將標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出重定向到/dev/null或日志文件中,防止輸出到控制終端。

在守護(hù)進(jìn)程的主循環(huán)中執(zhí)行需要執(zhí)行的任務(wù)。


Linux基礎(chǔ)(二)——多進(jìn)程開(kāi)發(fā)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
吉林省| 车致| 卢氏县| 翁牛特旗| 邳州市| 锦州市| 大姚县| 湛江市| 永昌县| 湖北省| 平江县| 九台市| 沾化县| 凌源市| 宝山区| 南昌县| 兰西县| 徐闻县| 杭锦旗| 绥宁县| 怀安县| 虎林市| 瑞安市| 武城县| 洛浦县| 仲巴县| 青河县| 蛟河市| 镇平县| 曲阳县| 石楼县| 临邑县| 隆林| 靖西县| 舟山市| 青冈县| 西华县| 曲松县| 行唐县| 淅川县| 塔城市|