亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Linux進(jìn)程控制方式

 更新時間:2025年03月07日 15:22:21   作者:新綠MEHO  
本文詳細(xì)介紹了fork函數(shù)、寫時拷貝、進(jìn)程退出、進(jìn)程等待以及程序替換等概念,并通過實例代碼和圖解幫助理解這些概念

1.進(jìn)程創(chuàng)建

fork函數(shù)

#include <unistd.h>
pid_t fork(void);

返回值:自進(jìn)程中返回 0 ,父進(jìn)程返回子進(jìn)程 id ,出錯返回 -1

進(jìn)程調(diào)用 fork ,當(dāng)控制轉(zhuǎn)移到內(nèi)核中的 fork 代碼后,內(nèi)核做:

  • 1.分配新的內(nèi)存塊和內(nèi)核數(shù)據(jù)結(jié)構(gòu)給子進(jìn)程
  • 2.將父進(jìn)程部分?jǐn)?shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝至子進(jìn)程
  • 3.添加子進(jìn)程到系統(tǒng)進(jìn)程列表當(dāng)中
  • 4.fork返回,開始調(diào)度器調(diào)度

fork之后,誰先執(zhí)行完全由調(diào)度器決定?。。?/p>

fork的常規(guī)用法

1.一個父進(jìn)程希望復(fù)制自己,使父子進(jìn)程同時執(zhí)行不同的代碼段。例如,父進(jìn)程等待客戶端請求,生成子進(jìn)程來處理請求。

2.一個進(jìn)程要執(zhí)行一個不同的程序。例如子進(jìn)程從fork返回后,調(diào)用exec函數(shù)。

2.寫時拷貝

通常,父子代碼共享,父子再不寫入時,數(shù)據(jù)也是共享的,當(dāng)任意一方試圖寫入,便以寫時拷貝的方式各自一份副本。

具體見下圖:

為什么要有寫時拷貝?

1.因為有寫時拷貝技術(shù)的存在,父子進(jìn)程得以徹底分離,保證了進(jìn)程獨立性。

2.寫時拷貝是一種延遲申請技術(shù),可以提高整機(jī)內(nèi)存的使用率。

3.進(jìn)程終止

進(jìn)程退出的場景

  • 1.代碼運(yùn)行完畢,結(jié)果正確
  • 2.代碼運(yùn)行完畢,結(jié)果不正確
  • 3.代碼異常終止

進(jìn)程常見退出方法

1.正常終止(可以通過 echo $? 查看進(jìn)程退出碼)

  • 從main返回
  • 調(diào)用exit
  • 調(diào)用_exit

2.異常退出

ctrl + c,信號終止

_exit 函數(shù)

#include <unistd.h>
void _exit(int status);

參數(shù): status 定義了進(jìn)程的終止?fàn)顟B(tài),父進(jìn)程通過 wait 來獲取該值

說明:雖然 status 是 int ,但是僅有低 8 位可以被父進(jìn)程所用。所以 _exit(-1) 時,在終端執(zhí)行 $? 發(fā)現(xiàn)返回值是255 。

exit 函數(shù)

exit 最后也會調(diào)用 _exit , 但在調(diào)用_ exit 之前,還做了其他工作:

  • 1. 執(zhí)行用戶通過 atexit 或 on_exit 定義的清理函數(shù)。
  • 2. 關(guān)閉所有打開的流,所有的緩存數(shù)據(jù)均被寫入
  • 3. 調(diào)用 _exit

實例:

int main()
{
printf("hello");
exit(0);
}
運(yùn)行結(jié)果 :
[root@localhost linux]# ./a.out
hello[root@localhost linux]#
------------------------------------------------------------------------
int main()
{
printf("hello");
_exit(0);
}
運(yùn)行結(jié)果 :
[root@localhost linux]# ./a.out
[root@localhost linux]#

通過上邊的例子,我們看到當(dāng)printf中的字符串后邊沒有加 \n 時,調(diào)用exit函數(shù)會打印出字符串內(nèi)容,但是調(diào)用 _exit 函數(shù)并不會打印任何內(nèi)容,原因就是因為 exit 底層調(diào)用的是 _exit,exit在調(diào)用_exit之前,會刷新緩沖區(qū),表現(xiàn)為原來緩沖區(qū)中的字符串被打印出來,但是 _exit并不會刷新緩沖區(qū)。

那么這個所謂的“緩沖區(qū)”在哪里呢?誰來維護(hù)的?

一定不在操作系統(tǒng)內(nèi)部??!如果是操作系統(tǒng)維護(hù)的,緩沖區(qū)內(nèi)的內(nèi)容也能被 _exit 刷新來。

C標(biāo)準(zhǔn)庫給我們維護(hù)的?。?!

退出碼

int main()
{
	int i;
	for(i=0;i<150;i++)
	{
		printf("%d: %s\n",i,strerror(i));
	}

	return 0;
}

通過上圖,可以看出,一共有134個退出碼。

4.進(jìn)程等待

進(jìn)程等待的必要性

1.之前講過,子進(jìn)程退出,父進(jìn)程如果不管不顧,就可能造成‘僵尸進(jìn)程’的問題,進(jìn)而造成內(nèi)存泄漏。

2.另外,進(jìn)程一旦變成僵尸狀態(tài),那就刀槍不入,“殺.人不眨眼”的kill -9 也無能為力,因為誰也沒有辦法殺死一個已經(jīng)死去的進(jìn)程。

3.最后,父進(jìn)程派給子進(jìn)程的任務(wù)完成的如何,我們需要知道。如,子進(jìn)程運(yùn)行完成,結(jié)果對還是不對,或者是否正常退出。

4.父進(jìn)程通過進(jìn)程等待的方式,回收子進(jìn)程資源,獲取子進(jìn)程退出信息

進(jìn)程等待的方法

wait方法

#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);

返回值:

  • 成功返回被等待進(jìn)程pid,失敗返回-1。

參數(shù):

  • 輸出型參數(shù),獲取子進(jìn)程退出狀態(tài),不關(guān)心則可以設(shè)置成為NULL

waitpid方法

pid_ t waitpid(pid_t pid, int *status, int options);

返回值:

  • 當(dāng)正常返回的時候waitpid返回收集到的子進(jìn)程的進(jìn)程ID;
  • 如果設(shè)置了選項WNOHANG,而調(diào)用中waitpid發(fā)現(xiàn)沒有已退出的子進(jìn)程可收集,則返回0;
  • 如果調(diào)用中出錯,則返回-1,這時errno會被設(shè)置成相應(yīng)的值以指示錯誤所在;

參數(shù):

pid

  • Pid=-1,等待任一個子進(jìn)程。與wait等效。
  • Pid>0.等待其進(jìn)程ID與pid相等的子進(jìn)程。

status:

  • WIFEXITED(status): 若為正常終止子進(jìn)程返回的狀態(tài),則為真。(查看進(jìn)程是否是正常退出)
  • WEXITSTATUS(status): 若WIFEXITED非零,提取子進(jìn)程退出碼。(查看進(jìn)程的退出碼)

options:

  • WNOHANG: 若pid指定的子進(jìn)程沒有結(jié)束,則waitpid()函數(shù)返回0,不予以等待。若正常結(jié)束,則返回該子進(jìn)程的ID。

注意:

  • 1.如果子進(jìn)程已經(jīng)退出,調(diào)用wait/waitpid時,wait/waitpid會立即返回,并且釋放資源,獲得子進(jìn)程退出信息。
  • 2.如果在任意時刻調(diào)用wait/waitpid,子進(jìn)程存在且正常運(yùn)行,則進(jìn)程可能阻塞。
  • 3.如果不存在該子進(jìn)程,則立即出錯返回。

說明:

  • 1.wait和waitpid是系統(tǒng)調(diào)用!?。?/li>
  • 2. 父進(jìn)程等待子進(jìn)程,當(dāng)子進(jìn)程執(zhí)行 return / exit / _exit / 因為某種原因異常崩潰退出 后,子進(jìn)程會將自己的退出碼信息寫入自己的進(jìn)程控制塊(task_struct)中,此時,退出后的子進(jìn)程處于Z狀態(tài),此時代碼可以釋放,但是task_struct必須維護(hù),直到父進(jìn)程讀取信息完畢后,子進(jìn)程的task_struct才能釋放。
  • 3.父進(jìn)程通過 wait / waitpid 傳遞的參數(shù),就可以拿到子進(jìn)程的退出結(jié)果(退出碼等信息)。

驗證上邊說到的 “子進(jìn)程會將自己的退出碼信息寫入到自己的進(jìn)程控制塊中” :

獲取子進(jìn)程status

1.wait和waitpid,都有一個status參數(shù),該參數(shù)是一個輸出型參數(shù),由操作系統(tǒng)填充。

2.如果傳遞NULL,表示不關(guān)心子進(jìn)程的退出狀態(tài)信息。

3.否則,操作系統(tǒng)會根據(jù)該參數(shù),將子進(jìn)程的退出信息反饋給父進(jìn)程。

4.status不能簡單的當(dāng)作整形來看待,可以當(dāng)作位圖來看待,具體細(xì)節(jié)如下圖(只研究status低16比特位):

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>

int main()
{
	pid_t id=fork();
	if(id==0)
	{
		int cnt=5;
		while(cnt--)
		{
			printf("我是子進(jìn)程,pid: %d,ppid(): %d\n",getpid(),getppid());
		}
		exit(100);
	}
	else if(id>0)
	{
			printf("我是父進(jìn)程,pid: %d,ppid: %d\n",getpid(),getppid());
		int status=0;
		pid_t result = waitpid(-1,&status,0);
		if(result>0)
		{
            //printf("等待子進(jìn)程成功,status: %d\n",status>>8);
			printf("等待子進(jìn)程成功,status: %d\n",status>>8 & 0xFFFF);
		}
	}
	else
	{
		//fork error
	}
	return 0;
}

注意:獲取status時,一定要先右移8位再按位與0xFFFF,如果不這么做的話,結(jié)果為:

顯然與100不符,結(jié)果錯誤。(這就是為什么要將status右移8位再按位與0xFFFF)

將status右移8位再按位與0xFFFF后,結(jié)果為:

與100符合,結(jié)果正確。

當(dāng)然,還有別的方法,將 status>>8 & 0xFFFF 改為 WEXITSTATUS(status)。

5.進(jìn)程程序替換

替換原理

用 fork 創(chuàng)建子進(jìn)程后執(zhí)行的是和父進(jìn)程相同的程序 ( 但有可能執(zhí)行不同的代碼分支 ), 子進(jìn)程往往要調(diào)用一種 exec 函數(shù)以執(zhí)行另一個程序。當(dāng)進(jìn)程調(diào)用一種exec 函數(shù)時 , 該進(jìn)程的用戶空間代碼和數(shù)據(jù)完全被新程序替換 , 從新程序的啟動例程開始執(zhí)行。調(diào)用exec 并不創(chuàng)建新進(jìn)程 , 所以調(diào)用 exec 前后該進(jìn)程的 id 并未改變。

程序替換,上邊紫色方框這一部分沒有發(fā)生改變,改變的只是,把要替換的進(jìn)程加載到物理內(nèi)存,頁表重新建立了映射關(guān)系。

替換函數(shù)

其實有六種以 exec 開頭的函數(shù) , 統(tǒng)稱 exec 函數(shù):

execl,execlp,execle,execv,execvp,execvpe這六個函數(shù)是系統(tǒng)提供的基本封裝,底層調(diào)用的都是execve這個系統(tǒng)調(diào)用接口。

函數(shù)返回值問題

  • 這些函數(shù)如果調(diào)用成功則加載新的程序從啟動代碼開始執(zhí)行 , 不再返回。
  • 如果調(diào)用出錯則返回 -1。
  • 假設(shè)調(diào)用成功有返回值,但是這個返回值也是返回給原來調(diào)用這個exec*系列函數(shù)的進(jìn)程,但是原來的這個進(jìn)程已經(jīng)被程序替換掉了,所以也沒辦法返回,方法行不通。
  • 所以 exec 函數(shù)只有出錯的返回值而沒有成功的返回值。

命名理解

這些函數(shù)原型看起來很容易混 , 但只要掌握了規(guī)律就很好記。

  • l(list) : 表示參數(shù)采用列表
  • v(vector) : 參數(shù)用數(shù)組
  • p(path) : 有p自動搜索環(huán)境變量PATH
  • e(env) : 表示自己維護(hù)環(huán)境變量

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用Hyper-v虛擬機(jī)安裝Centos7

    使用Hyper-v虛擬機(jī)安裝Centos7

    本文詳細(xì)講解了使用Hyper-v虛擬機(jī)安裝Centos7的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • Linux報錯cannot?open?shared?object?file問題及解決

    Linux報錯cannot?open?shared?object?file問題及解決

    這篇文章主要介紹了Linux報錯cannot?open?shared?object?file問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • linux服務(wù)器上安裝jdk的兩種方法(yum+下載包)

    linux服務(wù)器上安裝jdk的兩種方法(yum+下載包)

    這篇文章主要給大家介紹了關(guān)于在linux服務(wù)器上安裝jdk的兩種方法,分別是利用yum安裝和從官網(wǎng)下載包安裝,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧
    2018-05-05
  • 深入理解Linux負(fù)載均衡LVS

    深入理解Linux負(fù)載均衡LVS

    LVS是Linux Virtual Server 的簡稱,也就是linux虛擬服務(wù)器。LVS 是一個實現(xiàn)負(fù)載均衡集群的開源軟件項目,LVS架構(gòu)從邏輯上可分為調(diào)度層、Server集群層和共享存儲
    2021-06-06
  • Linux進(jìn)程間通信--使用信號

    Linux進(jìn)程間通信--使用信號

    本篇文章主要介紹了Linux進(jìn)程間通信--使用信號的相關(guān)知識。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-04-04
  • Centos7服務(wù)器下啟動jar包項目的最佳方法

    Centos7服務(wù)器下啟動jar包項目的最佳方法

    這篇文章主要給大家分享介紹了關(guān)于Centos7服務(wù)器下啟動jar包項目的最佳方法,文中通過示例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Win10安裝Linux系統(tǒng)的教程圖解

    Win10安裝Linux系統(tǒng)的教程圖解

    這篇文章主要介紹了Win10安裝Linux系統(tǒng)的教程,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • Linux如何啟動SELinux

    Linux如何啟動SELinux

    這篇文章主要介紹了Linux如何啟動SELinux問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • ubuntu端向日葵鍵盤輸入卡頓問題及解決

    ubuntu端向日葵鍵盤輸入卡頓問題及解決

    這篇文章主要介紹了ubuntu端向日葵鍵盤輸入卡頓問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • linux Vim基本操作方法

    linux Vim基本操作方法

    Ubuntu的Vi也不好用,搞了個Vim用來學(xué)習(xí)了,簡單記錄下它的基本操作。還有一本相關(guān)的電子書可下載。
    2013-11-11

最新評論