Linux 進(jìn)程管理與程序開發(fā)

Linux 進(jìn)程管理與程序開發(fā)

進(jìn)程是Linux事務(wù)管理的基本單元椎瘟,所有的進(jìn)程均擁有自己獨(dú)立的處理環(huán)境和系統(tǒng)資源,進(jìn)程的環(huán)境有當(dāng)前系統(tǒng)狀態(tài)及其父進(jìn)程信息決定和組成愈涩。

  • 進(jìn)程環(huán)境及進(jìn)程屬性
  • 進(jìn)程管理及控制
  • LINUX 特殊進(jìn)程

7.1進(jìn)程環(huán)境及環(huán)境

7.1.1進(jìn)程資源

進(jìn)程是Linux系統(tǒng)下用戶層管理事物的基本單元望抽,每個(gè)進(jìn)程都有自己獨(dú)立的運(yùn)行空間。

為了更好的管理Linux所訪問的資源履婉,系統(tǒng)在內(nèi)核頭文件include/linux/sched.h中定義了結(jié)構(gòu)體 struct task_struct 來(lái)管理每個(gè)進(jìn)程的資源煤篙。

Linux內(nèi)核進(jìn)程結(jié)構(gòu)體
7.1.2 進(jìn)程狀態(tài)

雖然Linux操作系統(tǒng)是一個(gè)多用戶多任務(wù)的操作系統(tǒng),但對(duì)于單CPU系統(tǒng)來(lái)說毁腿,在某一個(gè)時(shí)刻辑奈,只能有一個(gè)進(jìn)程處于運(yùn)行狀態(tài),其他進(jìn)程都處于其他狀態(tài)已烤,等待系統(tǒng)資源鸠窗,各任務(wù)根據(jù)調(diào)度算法在這些狀態(tài)之間不停地切換。但由于CPU處理速率較快胯究,使用戶感覺每個(gè)進(jìn)程都完全獨(dú)立擁有整個(gè)系統(tǒng)塌鸯。
用戶級(jí)進(jìn)程擁有以下幾種狀態(tài):

  • 就緒
  • 運(yùn)行狀態(tài)
  • 等待狀態(tài)(可以被中斷)
  • 等待狀態(tài)(不可以被中斷)
  • 停止?fàn)顟B(tài)
  • 僵死狀態(tài)
用戶級(jí)進(jìn)程之間的狀態(tài)轉(zhuǎn)換關(guān)系圖
7.1.3 進(jìn)程基本屬性

與進(jìn)程相關(guān)的屬性包括進(jìn)程號(hào)(PID)、父進(jìn)程號(hào)(PPID)唐片、進(jìn)程組號(hào)(PGID)丙猬。

1:進(jìn)程號(hào)(PID)

進(jìn)程號(hào)是系統(tǒng)維護(hù)的唯一標(biāo)識(shí)一個(gè)進(jìn)程的正數(shù)涨颜,進(jìn)程號(hào)是無(wú)法再用戶層修改的。在Linux系統(tǒng)中茧球,系統(tǒng)的第一個(gè)用戶進(jìn)程為init進(jìn)程庭瑰,它的PID為1,其他的進(jìn)程PID以此增加抢埋。

getpid函數(shù) 獲取當(dāng)前進(jìn)程的PID 該函數(shù)在unistdd.h文件中聲明

執(zhí)行失敗 -1 ,錯(cuò)誤原因存儲(chǔ)于errno中,pid_t類型其實(shí)就是int類型

2:父進(jìn)程號(hào)(PPID)

任何進(jìn)程(除init進(jìn)程)都是由另一進(jìn)程創(chuàng)建弹灭,該進(jìn)程稱為被創(chuàng)建進(jìn)程的父進(jìn)程,被創(chuàng)建的進(jìn)程稱為子進(jìn)程揪垄,父進(jìn)程號(hào)無(wú)法在用戶層修改穷吮,父進(jìn)程的進(jìn)程號(hào)(PID)即為子進(jìn)程的父進(jìn)程號(hào)(PPID),用戶可以通過調(diào)用getppid函數(shù)來(lái)獲取當(dāng)前進(jìn)程的父進(jìn)程號(hào)(PPID)饥努,其函數(shù)定義在/unistd.h文件中捡鱼。

3: 進(jìn)程組號(hào)(PGID)

在Linux系統(tǒng)中,每個(gè)用戶都擁有用戶號(hào)(UID)和用戶組號(hào)(GUID);和用戶管理一樣酷愧,進(jìn)程也擁有自己的進(jìn)程號(hào)(PID)和進(jìn)程組號(hào)(PGID)驾诈。進(jìn)程組是一個(gè)或者多個(gè)進(jìn)程的集合。

它們與同一作業(yè)相關(guān)聯(lián)溶浴,可以接受來(lái)自同一終端的各種信號(hào)乍迄,每個(gè)進(jìn)程組都有唯一的進(jìn)程組號(hào),進(jìn)程組號(hào)可以在用戶層修改士败。

用戶可以通過調(diào)用 getpgid()函數(shù)來(lái)獲得指定的進(jìn)程的進(jìn)程組號(hào)(PGID)闯两。其函數(shù)定義在 unistd.h文件中

如果執(zhí)行失敗則返回 -1 ,錯(cuò)誤原因存儲(chǔ)在errno中谅将。

每個(gè)進(jìn)程組都可以有一個(gè)組長(zhǎng)進(jìn)程漾狼,組長(zhǎng)進(jìn)程的進(jìn)程組號(hào)等于其他進(jìn)程號(hào)。但組長(zhǎng)進(jìn)程可以先退出戏自,即只要在某個(gè)進(jìn)程中有一個(gè)進(jìn)程存在邦投,則該進(jìn)程組就存在伤锚,與其組長(zhǎng)進(jìn)程是否終止無(wú)關(guān)擅笔。進(jìn)程組的最后一個(gè)進(jìn)程可以終止,或者裝一道另一個(gè)進(jìn)程組屯援。

加入一個(gè)現(xiàn)有的組或者一個(gè)新的進(jìn)程組的系統(tǒng)調(diào)用函數(shù)setpgid(),其聲明如下:
int setpgid(pid_t pid猛们,pid_t pgid );

4:會(huì)話

會(huì)話(session)是一個(gè)或多個(gè)進(jìn)程組的集合。系統(tǒng)調(diào)用函數(shù)getsid用來(lái)獲取某個(gè)進(jìn)程的會(huì)話號(hào)SID

函數(shù):extern _pid_t getsid(_pid_t _pid)

某進(jìn)程的會(huì)話SID是可以修改的狞洋,函數(shù)setsid()用來(lái)創(chuàng)建新的會(huì)話弯淘。

函數(shù):extern _pid_t setsid(void);

如果調(diào)用進(jìn)程已經(jīng)是一個(gè)進(jìn)程組的組長(zhǎng),則此函數(shù)返回錯(cuò)誤吉懊。為了杜絕這種情況的發(fā)生庐橙,通常先調(diào)用fork創(chuàng)建子進(jìn)程假勿,然后使其父進(jìn)程終止,而子進(jìn)程則繼續(xù)态鳖,在子進(jìn)程中調(diào)用此函數(shù)转培。

如果調(diào)用此函數(shù)的進(jìn)程不是一個(gè)進(jìn)程組的組長(zhǎng),則此函數(shù)會(huì)創(chuàng)建一個(gè)新會(huì)話:

  • 該進(jìn)程會(huì)變成新會(huì)話首進(jìn)程(seesion leader)浆竭,會(huì)話首進(jìn)程是創(chuàng)建該會(huì)話的進(jìn)程浸须。
  • 該進(jìn)程成為一個(gè)新進(jìn)程組的組長(zhǎng)進(jìn)程。新進(jìn)程組PGID 是該調(diào)用進(jìn)程的PID
  • 該進(jìn)程沒有控制終端邦泄,如果在調(diào)用setsid之前該進(jìn)程就有一個(gè)控制終端删窒,那么這種聯(lián)系也會(huì)被中斷。
5: 控制終端

會(huì)話和進(jìn)程組有以下一些特點(diǎn):

  • 一個(gè)會(huì)話可以有一個(gè)控制終端顺囊,建立與控制終端連接的會(huì)話首進(jìn)程被稱為控制進(jìn)程肌索。
  • 一個(gè)會(huì)話中的幾個(gè)進(jìn)程組可被分成一個(gè)前臺(tái)進(jìn)程組合幾個(gè)后臺(tái)進(jìn)程組,如果一個(gè)會(huì)話有一個(gè)控制端包蓝,則它有一個(gè)前臺(tái)進(jìn)程組驶社。
  • 無(wú)論何時(shí)鍵入終端的終端鍵(DELETE或Ctrl+C),都會(huì)將中斷信號(hào)發(fā)送給前臺(tái)進(jìn)程組的所有進(jìn)程测萎;無(wú)論何時(shí)鍵入終端的退出鍵(Ctrl+\)亡电,都會(huì)將退出信號(hào)發(fā)送給前臺(tái)進(jìn)程組的所有進(jìn)程。
7.1.4 進(jìn)程用戶屬性

Linux 是權(quán)限有嚴(yán)格控制的操作系統(tǒng)硅瞧,某個(gè)進(jìn)程擁有的真實(shí)用戶號(hào)(RUID)份乒、真實(shí)用戶組號(hào)(RGID)、有效用戶號(hào)(EUID)腕唧、有效用戶組號(hào)(EGID)信息或辖。

在說道進(jìn)程用戶時(shí),需要將文件的擁有者與擁有者組加以區(qū)別枣接。

1:進(jìn)程真實(shí)用戶號(hào)(RUID)

對(duì)于進(jìn)程而言颂暇,創(chuàng)建該進(jìn)程的用戶UID(執(zhí)行此程序的用戶)為此程序真實(shí)用戶號(hào)RUID.可以通過getuid 函數(shù)來(lái)獲取當(dāng)前進(jìn)程的真實(shí)用戶號(hào)(RUID)

函數(shù): extern _uid_t getuid(void)

此函數(shù)無(wú)參數(shù),如果執(zhí)行成功將返回當(dāng)前進(jìn)程的UID但惶;如果執(zhí)行失敗則返回-1耳鸯,錯(cuò)誤原因存儲(chǔ)在errno中。

2:進(jìn)程有效用戶號(hào)(EUID)

EUID 主要用于權(quán)限檢查膀曾。

3:進(jìn)程用戶組號(hào)(GID)

創(chuàng)建進(jìn)程的用戶所在的組號(hào)為該進(jìn)程的進(jìn)程用戶組號(hào)(GID)县爬。可以通過調(diào)用getgid()函數(shù)來(lái)獲得當(dāng)前進(jìn)程的真實(shí)用戶組號(hào)添谊。

函數(shù):extern _uid_t getgid(void)

此函數(shù)無(wú)參數(shù)财喳,如果執(zhí)行成功將返回當(dāng)前進(jìn)程的GID;如果執(zhí)行失敗則返回-1 ,錯(cuò)誤原因存儲(chǔ)在errno中。

4:有效進(jìn)程用戶組號(hào)(EGID)

一般情況下耳高,EGID和GID 相同扎瓶,但是,當(dāng)某可執(zhí)行文件設(shè)置了setgid位泌枪,那么任何用戶(包括root用戶)運(yùn)行此程序時(shí)栗弟,其有效用戶組號(hào)EGID該為文件的擁有者所在組,其原來(lái)EUID類似工闺。

函數(shù):extern _uid_t getegid(void)
此函數(shù)無(wú)參數(shù)乍赫,如果執(zhí)行成功將返回當(dāng)前進(jìn)程的EGID;如果執(zhí)行失敗則返回-1 ,錯(cuò)誤原因存儲(chǔ)在errno中陆蟆。

7.2 進(jìn)程管理及控制

在開發(fā)應(yīng)用程序時(shí)雷厂,程序猿需要有效管理進(jìn)程。常見的進(jìn)程管理方式包括

  • 創(chuàng)建進(jìn)程
  • 獲取進(jìn)程信息
  • 設(shè)置進(jìn)程屬性
  • 執(zhí)行進(jìn)程
  • 退出進(jìn)程
  • 跟蹤進(jìn)程
7.2.1 創(chuàng)建進(jìn)程
1:fork函數(shù)介紹

在Linux環(huán)境下叠殷,創(chuàng)建進(jìn)程的主要方法是調(diào)用fork()函數(shù)改鲫。Linux下所有的進(jìn)程都有init(PID為1)直接或間接創(chuàng)建。

函數(shù):extern _pid_t frok(void);

此函數(shù)沒有參數(shù) 返回值如下:

  • 如果執(zhí)行成功林束,在父進(jìn)程中將返回子進(jìn)程(新創(chuàng)建的進(jìn)程)的PID像棘,類型為pid_t,在子進(jìn)程將返回0,以區(qū)別父子進(jìn)程壶冒。
  • 如果執(zhí)行失敗缕题,則在父進(jìn)程中返回-1,錯(cuò)誤原因存儲(chǔ)在errno中。

fork函數(shù)調(diào)用成功后胖腾,其子進(jìn)程會(huì)復(fù)制父進(jìn)程的幾乎所有信息(除PID等信息)烟零,主發(fā)復(fù)制父親進(jìn)程的代碼段、數(shù)據(jù)段咸作、BSS锨阿、堆、棧记罚、打開文件描述符墅诡。另外,子進(jìn)程從父進(jìn)程繼承下列屬性:實(shí)際用戶/組號(hào)桐智、有效用戶/組號(hào)末早、環(huán)境變量、堆文件的執(zhí)行時(shí)關(guān)閉標(biāo)志酵使,信號(hào)處理方式設(shè)置荐吉、信號(hào)掩碼焙糟、當(dāng)前工作目錄口渔、根目錄、文件模式創(chuàng)建掩碼穿撮、文件大小設(shè)置等缺脉。

2:創(chuàng)建子進(jìn)程應(yīng)用示例

子進(jìn)程從創(chuàng)建后和父進(jìn)程同時(shí)執(zhí)行痪欲,競(jìng)爭(zhēng)系統(tǒng)資源,子進(jìn)程在執(zhí)行位置為fork返回位置攻礼。

/*
 ============================================================================
 Name        : frok_example.c
 Author      : file_demo
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

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

int main(void) {

    pid_t pid;
    if((pid == fork())==-1){
        printf("fork error");
    }
    printf("bye!\n");

    return EXIT_SUCCESS;
}

以上可以看出业踢,fork函數(shù)后代碼在子進(jìn)程中也被執(zhí)行。實(shí)際上礁扮,其他代碼也在子進(jìn)程代碼段中知举,只是子進(jìn)程執(zhí)行位置為fork返回位置,其之前的代碼無(wú)法執(zhí)行罷了太伊。

/*
 * fork_example2.c
 *
 *  Created on: Mar 4, 2016
 *      Author: james
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(){

    pid_t pid;

    pid = fork();


    if(pid == -1){
        printf("fork process error\n");
    }else if(pid == 0){
        printf("fork process ok\n");
    }else {
        printf("main process\n");
    }


    return EXIT_SUCCESS;
}


3:對(duì)打開文件的處理

fork函數(shù)創(chuàng)建子進(jìn)程后雇锡,子進(jìn)程將復(fù)制父進(jìn)程的數(shù)據(jù)段、BBS段僚焦、代碼段锰提、堆空間、椃急空間立肘、文件描述符,而對(duì)于文件描述符關(guān)聯(lián)的內(nèi)核文件表項(xiàng)名扛,則采用共享的方式谅年。

案例如下:


/*
 * fork_example3.c
 *
 *  Created on: Mar 4, 2016
 *      Author: james
 */


include stdio.h
include stdlib.h
include unistd.h
include sys/types.h
include string.h
include fcntl.h
include sys/stat.h

int main(){

    pid_t pid;
    int fd;
    int i = 1;

    int status ;
    char *ch1 = "hello";
    char *ch2 = "world";
    char *ch3 = "IN";

    if((fd = open("text.txt",O_RDWR|O_CREAT,0644)) == -1){
            perror("parent open");
            exit(EXIT_FAILURE);
    }

    if(write(fd,ch1,strlen(ch1) == -1)){
        perror("parent write");
        exit(EXIT_FAILURE);
    }

    if(( pid = fork() )== -1){
        perror("fork");
        exit(EXIT_FAILURE);
    }else if (pid == 0){
        i = 2;
        printf("in child\n");
        printf("i = %d\n",i);
        if(write(fd,ch2,strlen(ch2))== -1)
            perror("child write error\n");

        return 0;

    }else{
        sleep(1);
        printf("in parent\n");
        printf("i = %d",i);
        if(write(fd,ch3,strlen(ch3)) == -1)
            perror("parent,write");
        wait(&status);
        return 0;
    }



}

案例說明:
在程序?qū)ξ募枋龇僮髦校高M(jìn)程手續(xù)打開創(chuàng)建文件test.txt 文件肮韧,接著向該文件中寫入ch1(hello)內(nèi)容踢故,然后父進(jìn)行等待1秒讓子進(jìn)程完成寫ch2(world),操作惹苗,1秒后殿较,父進(jìn)程再次寫入數(shù)據(jù)ch3(IN)。由文件test.txt內(nèi)容可以看出父子進(jìn)程共同對(duì)一個(gè)文件操作桩蓉,且寫入數(shù)據(jù)不交叉覆蓋淋纲,說明父子進(jìn)程共享文件偏移。

對(duì)變量i院究,在子進(jìn)程中進(jìn)程了第2次賦值(i= 2)洽瞬,其結(jié)果為2,而父進(jìn)程中i的值不變业汰,顯然伙窃,父子進(jìn)程各子擁有這一變量的副本,互相不影響样漆。

4:結(jié)合vfork測(cè)試全局?jǐn)?shù)據(jù)段與BSS段使用策略

vfork()函數(shù)創(chuàng)建新進(jìn)程時(shí)無(wú)需完全復(fù)制父進(jìn)程的地址空間为障,如果派生的進(jìn)程只執(zhí)行exec()函數(shù),則使用fork()從父進(jìn)程復(fù)制到子進(jìn)程的數(shù)據(jù)空間將不被使用。這樣效率非常低鳍怨,從而使得vfork非常有用呻右。根據(jù)父進(jìn)程數(shù)據(jù)空間的大小,vfork比f(wàn)ork可以很大程度上提高性能鞋喇。cfork只在需要的時(shí)候復(fù)制声滥,而一般采用與父進(jìn)程共享所有的資源的方式處理。

其函數(shù):extern _pid_t vfork(void);

vfork()在子進(jìn)程環(huán)境中返回0侦香,在父進(jìn)程環(huán)境中返回子進(jìn)程的進(jìn)程號(hào)落塑。

在執(zhí)行過程中,fork()和vfork()函數(shù)有一定的區(qū)別罐韩,fork函數(shù)是拷貝一個(gè)父進(jìn)程的副本芜赌,從而擁有自己獨(dú)立的代碼段、數(shù)據(jù)段伴逸、以及堆棽颍空間,即成為一個(gè)獨(dú)立的實(shí)體错蝴。而vfork是共享父進(jìn)程的代碼以及數(shù)據(jù)段洲愤。

案例示例:

/*
 * fork_vfork_example4.c
 *
 *  Created on: Mar 4, 2016
 *      Author: james
 */


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <error.h>
int glob = 6;
int main(){

    int var ;
    pid_t  pid;
    var = 88;
    printf("in beginning:\tglob = %d \tvar = %d\n",glob,var);

    if((pid = vfork())<0){
        perror("vfork");
        exit(EXIT_FAILURE);
    }else if(pid == 0 ){
        //printf("in child ,modify the var:glob++ var++\n");
        glob++;
        var++;
        printf("in child,printf the var == %d, glob == %d\n",var,glob);
        _exit(0);
    }else{
        printf("in parent,printf the var == %d, glob == %d\n",var,glob);
        return 0;
    }


}

5:在子函數(shù)調(diào)用vfork創(chuàng)建子進(jìn)程。

案例示例:

/*
 * fork_return_example4.c
 *
 *  Created on: Mar 4, 2016
 *      Author: james
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
void test(){
    int i =1;

    pid_t pid;

    pid = vfork();
    if(pid == -1){
        perror("vfork error");
        exit(EXIT_FAILURE);
    }else if (pid == 0){
        printf("pid == 0 getpid = %d,getppid = %d\n",getpid(),getppid());
        _exit(0);
    }else{
        printf("pid == other getpid = %d,getppid = %d\n",getpid(),getppid());
    }


}
void fun(){
    char buf[100];
    printf("buf len = %d\n",sizeof(buf));
    int i ;
    for(i = 0;i<100;i++){
            buf[i] = 0;
            printf("fun pid getpid = %d,getppid ==%d\n",getpid(),getppid());
    }


}
int main(){
    pid_t pid;
    test();
    fun();

    return EXIT_SUCCESS;
}

7.2.2 在進(jìn)程中運(yùn)行新代碼
1:函數(shù)功能介紹及應(yīng)用

在fork函數(shù)創(chuàng)建子進(jìn)程后顷锰,如果希望在當(dāng)前子進(jìn)程中運(yùn)行新程序柬赐,則可以調(diào)用exec系列函數(shù)。當(dāng)進(jìn)程調(diào)用exec系列函數(shù)中的任意一個(gè)時(shí)官紫,該進(jìn)程代碼段肛宋,數(shù)據(jù)內(nèi)容完全由新成效替代。因?yàn)檎{(diào)用exec并不是創(chuàng)建新進(jìn)程束世,所以前后的進(jìn)程號(hào)等相關(guān)信息并不發(fā)生變化酝陈。exec,只是用新程序替換了當(dāng)前進(jìn)程的正文毁涉、數(shù)據(jù)沉帮、堆和棧段。

execl 函數(shù):
extern int execl(_const char *_path,_const char *_arg ,...);
execl() 用來(lái)執(zhí)行參數(shù)path字符所代表的文件路徑(絕對(duì)路徑)贫堰,第二個(gè)參數(shù)代表執(zhí)行文件時(shí)傳遞的argv,最后一個(gè)參數(shù)必須是空指針穆壕。

案例示例:

/*
 ============================================================================
 Name        : exec_example.c
 Author      : file_demo
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

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

int main(void) {

    pid_t pid;
    if((pid = fork())<0 ){
        perror("fork error\n");
    }else if (pid == 0){
        //
        int  exec_resp = execl("/bin/ls","ls","-l","/home",(char)0);
        printf("exec_resp = %d\n",exec_resp);
        _exit(0);
    }else {
        //
        printf("");
    }
    return EXIT_SUCCESS;
}

execle函數(shù)聲明:
extern int execle(_const char *_path,_const char *_arg,...)
execle 用來(lái)執(zhí)行參數(shù)path 字符串所代表的文件路徑(絕對(duì)路徑),第二個(gè)參數(shù)代表執(zhí)行文件時(shí)傳遞的是argv其屏,最后一個(gè)參數(shù)必須指向一個(gè)新的環(huán)境變量數(shù)組喇勋,此數(shù)組即成為新執(zhí)行程序的環(huán)境變量。

/*
 * execle_example.c
 *
 *  Created on: Mar 4, 2016
 *      Author: james
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main( int argc, char *argv[],char *env[]){


    execle("/bin/ls","ls","-l","/home",(char *)0,env);

    return EXIT_SUCCESS;
}

execlp()函數(shù)聲明
extern int execlp(_const char *_file,_const char *_arg,...)
execlp()會(huì)從PATH環(huán)境變量所指的目錄中查找符合參數(shù)file的文件名偎行,找到后執(zhí)行該文件川背,第二個(gè)參數(shù)代表執(zhí)行文件時(shí)傳遞的argv[0],最后一個(gè)參數(shù)必須用空指針NULL贰拿。

案例示例:

/*
 * execlp_example.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */


include <unistd.h>
include <stdio.h>
include <stdlib.h>


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

    execlp("ls","ls","-l","/home",(char)0);
    return EXIT_SUCCESS;
}

execvp() 函數(shù)聲明

extern int execvp(_const char *_file ,char *_const _argv[]);

除以上函數(shù)外,system()以新進(jìn)程方式運(yùn)行一個(gè)程序渗常。然后結(jié)束。system()函數(shù)用來(lái)創(chuàng)建新進(jìn)程汗盘,并再次進(jìn)程中運(yùn)行新進(jìn)程皱碘,知道新進(jìn)程結(jié)束后,才繼續(xù)運(yùn)行父進(jìn)程隐孽,子進(jìn)程結(jié)束后癌椿,會(huì)返回退出狀態(tài),(如wait一樣)菱阵。
其函數(shù)定義如下:
extern int system (_const char *_command);

案例示例:

/*
 * system_example.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(){

    int status;
    status =  system("pwd");
    if(!WIFEXITED(status)){
        printf("abnormal exit\n");
    }else{
        printf("the exit status is %d\n",status);
    }
    return 0;
}

2:執(zhí)行新代碼對(duì)打開文件的處理

案例示例:


include <unistd.h>
include <stdio.h>
include <stdlib.h>
 
int main(int argc, char *argv[]){

    int i;
    int fd;
    char *ptr = "hello world\n";
    fd = atoi (argv[1]);
    i = write(fd,ptr,strlen(ptr));
    if(i<=0){
        perror("write\n");
    }
    return EXIT_SUCCESS;
}

/*
 * fcntl_example.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */

include <stdio.h>
include <stdlib.h>
include <unistd.h>
include <sys/types.h>
include <fcntl.h>
include <string.h>

int main(){

    int fd ,status;
    pid_t pid;

    fd = open("text.txt",O_RDWR|O_CREAT,0644);
    if(fd == -1){
        perror("open error");
        exit(EXIT_FAILURE);
    }

    printf("befor child process write\n");
    system("cat text.txt");
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }else if(pid == 0){
        char buf[128];
        sprintf(buf,"%d",fd);
        execl("./newcode","newcode","buf",(char)0);
    }else{
        wait(&status);
        printf("after child_preccess write\n");
        system("cat text.txt");
    }
    return EXIT_SUCCESS;
}

7.2.3 等待進(jìn)程結(jié)束

進(jìn)程與進(jìn)程間要進(jìn)程信息的狀態(tài)的傳遞與交互踢俄,必須使用進(jìn)程間通信機(jī)制,Linux使用函數(shù)wait()和waitpid()在父子進(jìn)程間提供了簡(jiǎn)單的父子進(jìn)程間同步機(jī)制晴及。

1:wait 等待子進(jìn)程結(jié)束

調(diào)用 wait() 函數(shù)的父進(jìn)程將等待該進(jìn)程的任意一個(gè)子進(jìn)程結(jié)束后才繼續(xù)執(zhí)行都办,如果有多個(gè)子進(jìn)程,只需要等待其中的進(jìn)程虑稼。其函數(shù)定義在/use/include/sys/wait.h文件中琳钉。

函數(shù)聲明為:extern _pid_t wait (_WAIT_STATUS _stat_loc);//wait 函數(shù)

如果等到任意一個(gè)子進(jìn)程結(jié)束,將返回當(dāng)前結(jié)束的子進(jìn)程的PID蛛倦,同時(shí)將子進(jìn)程退出時(shí)的狀態(tài)存儲(chǔ)到“——stat_loc”變量中歌懒。如果執(zhí)行失敗則返回-1,錯(cuò)誤原因存儲(chǔ)在 errno 中溯壶。

案例示例:

/*
 * wait_example.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

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

    pid_t pid_one ,pid_wait;
    int status;
    if((pid_one = fork()) == -1){
        perror("fork error");
    }else if(pid_one == 0){
        printf("my pid is %d\n",getpid());
        sleep(1);
        exit(EXIT_SUCCESS);
    }else{
        pid_wait =  wait(&status);
        if(WIFEXITED(status)){
            printf("wait on pid:%d return value is;%4x\n",pid_wait,WEXITSTATUS(status));
        }else if(WIFSIGNALED(status)){
            //printf("wait on pid :%d return value is:%4x\n",pid_wait,WIFSIGNALED(status));
        }
    }
    return EXIT_SUCCESS;
}


2:waitpid() 等待子進(jìn)程結(jié)束

用戶可以使用waitpid()函數(shù)來(lái)等待指定子進(jìn)程(指定PID的子進(jìn)程)結(jié)束及皂。

其函數(shù)定義/usr/include/sys/Wait.h
extern _pid_t waitpid (_pid_t _pid,int *_stat_loc,int _options);
其中,

第一個(gè)參數(shù)為進(jìn)程PID值且改,該值的設(shè)置范圍如下:

  • PID > 0 ,表示等待進(jìn)程PID 為該P(yáng)ID 值的進(jìn)程結(jié)束验烧。
  • PID =-1 ,表示等待任意進(jìn)程結(jié)束
  • PID = 0 ,表示等待與當(dāng)前進(jìn)程的進(jìn)程組PGID一致的進(jìn)程結(jié)束
  • PID <-1 ,表示等待進(jìn)程組PGID是此值的絕對(duì)值的進(jìn)程結(jié)束

第二個(gè)參數(shù)為調(diào)用它的函數(shù)中某個(gè)變量地址,如果執(zhí)行成功又跛,則用來(lái)存儲(chǔ)結(jié)束進(jìn)程的結(jié)束狀態(tài)噪窘。

第三個(gè)參數(shù)為等待選項(xiàng),可以設(shè)置為0效扫,亦可為WNOHANG和WUNTRACED 定義如下:

define WNOHANG 1

define WUNTRACED 2

如果OPTIONS 設(shè)置為WNOHANG倔监,而此時(shí)沒有子進(jìn)程退出,將返回0菌仁,而返回子進(jìn)程的PID浩习,并獲取子進(jìn)程的狀態(tài)于參數(shù)STAT_LOC中。

waitpid 與 wait 的使用方法類似济丘,因此可以將wait示例中的wait語(yǔ)句換成以下代碼:

pid_wait= waitpid(pid_one,&status,0);

7.2.4 退出進(jìn)程

在LINUX 下谱秽,可以通過以下方式結(jié)束進(jìn)程

  • 向exit或_exit發(fā)布一個(gè)調(diào)用
  • 在main函數(shù)中執(zhí)行return
  • 隱含的離開main函數(shù)

LINUX常用的退出進(jìn)程函數(shù)有exit()洽蛀、_exit()和on_exit()

1:abort 中止進(jìn)程

abort 函數(shù)用來(lái)中止進(jìn)程。函數(shù)聲明

extern void abort (void)

2:atexit 退出進(jìn)程

注冊(cè)一個(gè)函數(shù)在exit退出時(shí)調(diào)用疟赊。函數(shù)聲明

extern int atexit(void(* _func)(void))

3:on_exit正常退出進(jìn)程

正常結(jié)束當(dāng)前調(diào)用函數(shù)郊供。其函數(shù)聲明

extern int on_exit(void(*_func)(int status,void *arg)void *arg);

on_exit()用來(lái)設(shè)置一個(gè)程序正常結(jié)束前調(diào)用的函數(shù),當(dāng)程序通過調(diào)用exit()或者從main中返回時(shí)近哟,參數(shù)func所指定的函數(shù)先被調(diào)用驮审,然后才真正由exit()結(jié)束程序,參數(shù)arg指針會(huì)傳給func函數(shù)疯淫。

如果執(zhí)行成功則返回0,否則返回-1,錯(cuò)誤原因存儲(chǔ)在errno中肌似。

案例示例:

/*
 ============================================================================
 Name        : exit_example.c
 Author      : file_demo
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>

void test_exit(int status ,void *arg){
    printf("before exit()\n");
    printf("exit %d\n",status);
    printf("arg = %s\n",(char *)arg);
}

int main(void) {

    char *str = "test";
    on_exit(test_exit,(void *)str);
    exit(4321);
    return EXIT_SUCCESS;
}

4:exit退出進(jìn)程

函數(shù)exit用于退出進(jìn)程。其函數(shù)聲明如下:

extern void exit(int _status);

exit()用來(lái)正常結(jié)束當(dāng)前進(jìn)程的執(zhí)行笛臣,并把參數(shù)status返回給父進(jìn)程鲸拥,而進(jìn)程所有的緩沖區(qū)數(shù)數(shù)據(jù)會(huì)自動(dòng)寫回并關(guān)閉文件。

如果執(zhí)行成功沒有返回值沛申,否則返回-1 ,失敗原因存儲(chǔ)在errno中惊暴。

5:exit 與 return 區(qū)別

C 語(yǔ)言關(guān)鍵字與函數(shù)益咬,exit()在main函數(shù)退出時(shí)有相似之處,但兩者本質(zhì)的區(qū)別:

  • return退出當(dāng)前函數(shù)主體,exit()函數(shù)退出當(dāng)前進(jìn)程全封,因此桃犬,在main函數(shù)里面return(0)和exit(0)完成一樣的功能攒暇。
  • return僅僅從子函數(shù)中返回乎莉,而子進(jìn)程用exit()退出肥橙,調(diào)用exit()時(shí)要調(diào)用一段終止處理程序,然后關(guān)閉所有的IO流
6:_exit 不調(diào)用任何注冊(cè)函數(shù)退出進(jìn)程味榛,其函數(shù)聲明如下:

extern void _exit(int _status)

_exit()用來(lái)正常結(jié)束當(dāng)前進(jìn)程的執(zhí)行椭坚,把參數(shù)status返回給父進(jìn)程,并關(guān)閉文件搏色。此函數(shù)調(diào)用后不會(huì)返回善茎,而傳遞SIGHLD信號(hào)給父進(jìn)程,父進(jìn)程可以通過wait函數(shù)取得獲得子進(jìn)程的結(jié)束狀態(tài)频轿,exit()不會(huì)處理標(biāo)準(zhǔn)的IO緩沖區(qū)垂涯,如果要更新需要調(diào)用exit().

7.2.5 修改進(jìn)程用戶相關(guān)信息
1:access 核實(shí)用戶權(quán)限

此函數(shù)用來(lái)檢查真實(shí)用戶號(hào)(UID)或真實(shí)用戶組號(hào)(GID)是否擁有對(duì)文件的相應(yīng)訪問權(quán)限烁焙。

函數(shù)定義:extern int access (_const char *_name ,int type);

此函數(shù)的第一餓參數(shù)為欲訪問的文件(需要包含路徑),第二參數(shù)為相應(yīng)的訪問權(quán)限耕赘,文件權(quán)限定義如下:

  • define R_OK 4
  • define W_OK 2
  • define X_OK 1
  • define F_OK 0

如果文件具有測(cè)試權(quán)限骄蝇,此函數(shù)將返回0,否則返回-1,其錯(cuò)誤狀態(tài)主要有以下幾個(gè):

  • EACCESS :不具有指定的訪問權(quán)限
  • ENOENT :文件不存在
  • EROFS :在只讀文件系統(tǒng)要求寫權(quán)限操骡。

案例示例:

/*
 * access_example.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */

include < stdio.h >
include < stdlib.h >
include < unistd.h >

int main(){
    int i ;
    if(i == access("/etc/exports",X_OK) == -1){// 檢查是否有執(zhí)行的檢驗(yàn)
        perror("access");
        exit(EXIT_FAILURE);
    }else{
        printf("the user have write permission\n");
    }
    return 0;
}

2:設(shè)置進(jìn)程真實(shí)用戶RUID

如果要顯示修改此值九火,可以調(diào)用setuid函數(shù)。

函數(shù)聲明

extern int setuid(_uid_t _uid);

此函數(shù)有一個(gè)參數(shù)册招,即設(shè)置進(jìn)程真實(shí)用戶號(hào)(RUID):

  • 如果當(dāng)前用戶是超級(jí)用戶岔激,則將設(shè)置真實(shí)用戶號(hào)(UID)、有效用戶號(hào)EUID為指定ID是掰,并返回0 以標(biāo)識(shí)成功虑鼎。
  • 如果當(dāng)前用戶是普通用戶,且設(shè)置UID值為自己的UID冀惭,則可以修改成功震叙,否則無(wú)權(quán)修改掀鹅,函數(shù)江返回-1

案例示例:

/*
 * setuid_exp.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){

    int uid,euid,suid;
    getresuid(&uid,&euid,&suid);
    printf("uid = %d,euid = %d,suid = %d\n",uid,euid,suid);
    printf("after setuid(501)\n");
    setuid(501); //執(zhí)行此程序 普通用戶無(wú)法修改
    uid = 1; euid = -1; suid = -1;
    getresuid(&uid,&euid,&suid);
    printf("uid == %d,euid = %d,suid = %d\n",uid,euid,suid);
    return 0;

}

3 設(shè)置進(jìn)程有效用戶EUID

由前面可知散休,某個(gè)進(jìn)程的EUID首先由該可執(zhí)行文件的權(quán)限決定,如果該可執(zhí)行文件設(shè)置setuid位乐尊,則EUID為執(zhí)行此進(jìn)程的用戶戚丸;如果該可執(zhí)行文件設(shè)置setuid位,則EUID為該可執(zhí)行文件的擁有者扔嵌。

函數(shù)setuid 用來(lái)設(shè)置有效用戶號(hào)(EUID)

函數(shù)聲明
extern int seteuid(_uid_t uid);

  • 如果是超級(jí)用戶限府,將設(shè)置有效用戶號(hào)(EUID)為指定ID。如果調(diào)用成功痢缎,該函數(shù)將返回0胁勺;如果調(diào)用失敗,將返回-1 并有以下錯(cuò)誤代碼設(shè)置独旷。
  • 如果是普通用戶署穗,可以設(shè)置EUID為自己的ID,如果想設(shè)置為其他用戶則不予更改嵌洼,將返回失敗案疲,此外,還可以調(diào)用setegid來(lái)設(shè)置音效egid

setegid 函數(shù)可以用來(lái)設(shè)置有效組ID麻养,原理與seteuid類型褐啡,函數(shù)聲明如下:

extern int setegid(__gid_t ,_gid)

案例示例:

/*
 * setuid_exp.c
 *
 *  Created on: Mar 5, 2016
 *      Author: james
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){

    int uid,euid,suid;
    getresuid(&uid,&euid,&suid);
    printf("uid = %d,euid = %d,suid = %d\n",uid,euid,suid);
    printf("after setuid(501)\n");
    setuid(501);
    setreuid(0,500);
    uid = 1; euid = -1; suid = -1;
    getresuid(&uid,&euid,&suid);
    printf("uid == %d,euid = %d,suid = %d\n",uid,euid,suid);
    return 0;

}

7.2.6 進(jìn)程調(diào)度管理函數(shù)

每個(gè)進(jìn)程都受調(diào)度策略和優(yōu)先級(jí)的控制。這些參數(shù)可以通過應(yīng)用程序顯式執(zhí)行 sched_setscheduler()或通過sched_setparam()函數(shù)來(lái)指定(這些函數(shù)可以按進(jìn)程級(jí)別為多進(jìn)程更改調(diào)度參數(shù))鳖昌。

優(yōu)先級(jí)范圍與每種策略相關(guān)备畦。每種策略的優(yōu)先級(jí)范圍可以(但不需要)與其他策略的優(yōu)先級(jí)范圍重疊低飒。選擇要運(yùn)行的進(jìn)程時(shí),將選擇位于最高優(yōu)先級(jí)非空進(jìn)程列表首位的進(jìn)程懂盐,然后逸嘀,該進(jìn)程會(huì)從其他進(jìn)程列表中刪除。

在常見操作系統(tǒng)中允粤,調(diào)度算法主要有以下原則:

  • FIFO 先入先出原則:首先請(qǐng)求服務(wù)的對(duì)象首先得到CPU的處理崭倘;
  • 最短作業(yè)優(yōu)先原則:需要最小系統(tǒng)時(shí)間的服務(wù)首先得到處理;
  • 最高優(yōu)先級(jí)優(yōu)先原則:優(yōu)先級(jí)最高的服務(wù)首先得到處理类垫;
  • 時(shí)間輪片原則司光;每個(gè)任務(wù)分配一個(gè)系統(tǒng)時(shí)間片,輪流執(zhí)行悉患;
1: 設(shè)置調(diào)度策略

設(shè)置調(diào)度策略sched_setscheduler 函數(shù)聲明:

extern int sched_setscheduler (_pid_t __Pid,int policy,_const struct sched_param *__param);

sched_setscheduler()函數(shù)將pid所指定進(jìn)程的調(diào)度策略和調(diào)度參數(shù)分別設(shè)置為param指向的sched_param結(jié)構(gòu)中的policy及其參數(shù)残家。param結(jié)構(gòu)中的sched_priority成員的值可以為任何整數(shù),該整數(shù)位于policy所指定調(diào)度策略的優(yōu)先級(jí)范圍內(nèi)(含邊界值)售躁。policy參數(shù)的可能值在頭文件<sched.h>中定義坞淮。

  • 如果存在pid所描述的進(jìn)程,將會(huì)為進(jìn)程ID等pid的進(jìn)程設(shè)置調(diào)度策略和調(diào)度參數(shù)陪捷。
  • 如果pid為零回窘,將會(huì)為調(diào)用進(jìn)程設(shè)置調(diào)用策略和調(diào)度參數(shù)。
  • 如果進(jìn)程pid含多個(gè)進(jìn)程或輕量進(jìn)程(即該進(jìn)程時(shí)多進(jìn)程的)市袖,此函數(shù)將會(huì)影響進(jìn)程中各個(gè)內(nèi)核可調(diào)用實(shí)體的策略和優(yōu)先級(jí)啡直,具體取決于調(diào)度爭(zhēng)用范圍。

對(duì)于使用系統(tǒng)爭(zhēng)用范圍創(chuàng)建的進(jìn)程苍碟,此系統(tǒng)調(diào)用將不會(huì)對(duì)進(jìn)程或基礎(chǔ)內(nèi)核調(diào)度實(shí)體的調(diào)度產(chǎn)生影響酒觅。

對(duì)于使用進(jìn)程爭(zhēng)用范圍的進(jìn)程,進(jìn)程的調(diào)度參數(shù)不會(huì)受到影響微峰。但是進(jìn)程爭(zhēng)用范圍進(jìn)程的基礎(chǔ)內(nèi)核調(diào)度實(shí)體會(huì)將其調(diào)度參數(shù)改為參數(shù)中指定的值舷丹,進(jìn)程爭(zhēng)用范圍進(jìn)程使用的內(nèi)核調(diào)度實(shí)體(在此調(diào)用完成之后創(chuàng)建)從進(jìn)程繼承調(diào)度策略和相關(guān)調(diào)度參數(shù)。

返回的優(yōu)先級(jí)為目標(biāo)進(jìn)程的舊優(yōu)先級(jí)蜓肆,但是如果使用某些其他接口更改各個(gè)進(jìn)程或輕量進(jìn)程的優(yōu)先級(jí)颜凯,各個(gè)進(jìn)程或輕量進(jìn)程可能具有其他值。

更改其他進(jìn)程的調(diào)度參數(shù)需要有相應(yīng)的特權(quán)症杏。調(diào)用進(jìn)程必須具有相應(yīng)的特權(quán)装获,或者是具有PRIV_STSCHED權(quán)限的組的成員,才能夠調(diào)用sched_setscheduler();

/*
 ============================================================================
 Name        : sched_setscheduler.c
 Author      : sched_setscheduler
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <sched.h>

int main(void) {

    struct sched_param param;
    int maxpri;
    maxpri = sched_get_priority_max(SCHED_FIFO);// 獲取最大值
    if(maxpri == -1){
        perror("sched_get_priority_max() failed");
        exit(1);
    }

    param.sched_priority = maxpri;

    if(sched_setscheduler(getpid(),SCHED_FIFO,&param) == -1){//設(shè)置優(yōu)先級(jí)
        perror("sched_setscheduler() failed");
        exit(1);
    }
    return EXIT_SUCCESS;
}

2:獲取調(diào)度策略

獲取調(diào)度策略sched_getscheduler ()函數(shù)聲明如下:

extern int sched_getscheduler(_pid_t __pid)

sched_getscheduler()函數(shù)返回pid所指定進(jìn)程的調(diào)度策略厉颤。

  • 如果存在pid所描述的進(jìn)程穴豫,將返回進(jìn)程ID 等pid的進(jìn)程的調(diào)度策略。
  • 如果pid為零,將返回調(diào)用進(jìn)程的調(diào)度策略
  • 如果pid包含多個(gè)進(jìn)程或輕量進(jìn)程精肃,此函數(shù)只返回進(jìn)程調(diào)度策略和優(yōu)先級(jí)秤涩。目標(biāo)進(jìn)程中的各個(gè)進(jìn)程或輕量進(jìn)程具有其自身的調(diào)度策略和優(yōu)先級(jí),它們可能與進(jìn)度的調(diào)度策略和優(yōu)先級(jí)不同司抱。
3:設(shè)置調(diào)度參數(shù)

可以使用sched_getparam 設(shè)置調(diào)度參數(shù)筐眷,其函數(shù)聲明如下:

extern int sched_getparam(__pid_t __pid,struct sched_param *_param);

sched_setparam函數(shù)將pid指定進(jìn)程的調(diào)度參數(shù)設(shè)置為param指向的sched_param結(jié)構(gòu)指定的值。

sched_param結(jié)構(gòu)定義如下:

struct sched_param{
    int sched_priority;
}

param 結(jié)構(gòu)中的sched_priority成員的值可以為任何整數(shù)习柠,該整數(shù)位于pid指定進(jìn)程當(dāng)前調(diào)度策略的優(yōu)先級(jí)范圍內(nèi)(含邊界值)匀谣,該優(yōu)先級(jí)的數(shù)值越大表示優(yōu)先級(jí)越高(越強(qiáng))。

如果存在pid所描述的進(jìn)程资溃,并且調(diào)用進(jìn)程具有權(quán)限武翎,將為進(jìn)程ID等于pid 的進(jìn)程設(shè)置調(diào)度參數(shù)。如果pid為零溶锭,將為調(diào)用進(jìn)程設(shè)置調(diào)度參數(shù)宝恶。

如果進(jìn)程的pid包含多個(gè)進(jìn)程或輕量進(jìn)程鞠评,此函數(shù)將會(huì)影響進(jìn)程中各個(gè)內(nèi)核可調(diào)度實(shí)體的策略和優(yōu)先級(jí)惰爬,具體取決于調(diào)度爭(zhēng)用范圍郭厌。

  • 對(duì)使用系統(tǒng)爭(zhēng)用范圍創(chuàng)建的進(jìn)程哨免,此系統(tǒng)調(diào)用不會(huì)對(duì)進(jìn)程或基礎(chǔ)內(nèi)核調(diào)度實(shí)體的調(diào)度產(chǎn)生影響。
  • 對(duì)于使用進(jìn)程爭(zhēng)用范圍的進(jìn)程耀石,進(jìn)程的調(diào)度參數(shù)不會(huì)受到影響忘蟹。但是進(jìn)程爭(zhēng)用范圍進(jìn)程的基礎(chǔ)內(nèi)核調(diào)度實(shí)體會(huì)將其調(diào)度參數(shù)改為參數(shù)中指定的值朴恳。進(jìn)程爭(zhēng)用范圍進(jìn)程使用的內(nèi)核調(diào)度實(shí)體(在此調(diào)用完成之后創(chuàng)建)從進(jìn)程繼承調(diào)度策略和相關(guān)調(diào)度參數(shù)欺栗。
  • 對(duì)于單進(jìn)程的進(jìn)程毫痕,其調(diào)度參數(shù)也將會(huì)更改征峦。

只有超級(jí)用戶才能更改其他進(jìn)程的調(diào)度參數(shù)迟几。調(diào)用進(jìn)程必須具有相應(yīng)的特權(quán)。

4:讀取調(diào)度參數(shù)

可以使用sched_getparam 設(shè)置調(diào)度參數(shù):
extern int sched_setparam(_pid_tm_const struct sched_param *_param);
sched_getparam()函數(shù)返回進(jìn)程的調(diào)度參數(shù)(該進(jìn)程由param指向sched_param 結(jié)構(gòu)中pid指定)栏笆。

5:放棄進(jìn)程

extern int sched_yield(void)
sched_yield()函數(shù)強(qiáng)制調(diào)用進(jìn)程放棄處理器类腮,直到調(diào)用進(jìn)程再次位于進(jìn)程列表的首位。該函數(shù)不帶參數(shù)蛉加。

6:獲取優(yōu)先級(jí)值的范圍

sched_get_priority_max()和 sched_get_priority_main()函數(shù)分別為algorithm指定的調(diào)度策略返回的相應(yīng)最大值和最小值蚜枢。

7:獲取進(jìn)程的執(zhí)行時(shí)間限制
8:獲取進(jìn)程優(yōu)先級(jí)
9:設(shè)置進(jìn)程優(yōu)先級(jí)

7.3Linux特殊進(jìn)程

7.3.1守候進(jìn)程及其創(chuàng)建過進(jìn)程
1:守候進(jìn)程的特點(diǎn)

守護(hù)進(jìn)程(Daemon)是在后臺(tái)進(jìn)程的一種特殊進(jìn)程,脫離于終端针饥。

一般情況下,守護(hù)進(jìn)程可以通過以下方式啟動(dòng):

  • 在系統(tǒng)啟動(dòng)時(shí)由腳本啟動(dòng)厂抽,這些啟動(dòng)腳本通常放在/etc/rc.d目錄下
  • 利用inetd超級(jí)服務(wù)器啟動(dòng),如telnet等丁眼。
  • 由cron定時(shí)啟動(dòng)以及在終端nohup啟動(dòng)進(jìn)程也是守護(hù)進(jìn)程筷凤。
2:守護(hù)進(jìn)程編程要點(diǎn)

下面是編寫守護(hù)進(jìn)程的基本過程:

  • (1)屏蔽一些有關(guān)控制端的信號(hào),這是為了防止在守護(hù)進(jìn)程沒有正常運(yùn)行起來(lái)前,控制終端受到干擾退出或掛起:
  • (2)在后臺(tái)運(yùn)行藐守。 這是為了避免掛起控制終端將其放入后臺(tái)執(zhí)行挪丢。方法是在進(jìn)程中調(diào)用fork使其fork使父進(jìn)程終止,讓其子進(jìn)程中后臺(tái)執(zhí)行卢厂。
  • (3)脫離控制終端和進(jìn)程組乾蓬,應(yīng)為進(jìn)程屬于一個(gè)進(jìn)程組,進(jìn)程組號(hào)(PGID)就是進(jìn)程組長(zhǎng)的進(jìn)程號(hào)(PID)慎恒。同進(jìn)程組中進(jìn)程共享一個(gè)控制終端任内,這個(gè)控制終端通常是創(chuàng)建進(jìn)程的shell登陸終端。而控制終端和進(jìn)程組通常是父進(jìn)程繼承下來(lái)的融柬,需要擺脫它們族奢,使之不受它們的影響。因此需要調(diào)用setsid使子進(jìn)程成為新的會(huì)話組長(zhǎng)
    案例示例:
    setsid調(diào)用成功后丹鸿,調(diào)用進(jìn)程會(huì)成為新的會(huì)話組長(zhǎng)和新的進(jìn)程組長(zhǎng)越走,并于原來(lái)的登錄會(huì)話和進(jìn)程組脫離,由于會(huì)話過程對(duì)控制終端的獨(dú)占性靠欢,進(jìn)程同時(shí)與控制終端脫離廊敌。
  • (4)禁止進(jìn)程重新打開控制終端。
  • (5)關(guān)閉打開的文件描述符门怪。
  • (6)改變當(dāng)前工作目錄骡澈。
  • (7)重設(shè)文件創(chuàng)建淹模。
  • (8)處理SIGGHLD信號(hào)(子進(jìn)程退出信號(hào))掷空。但對(duì)于某些進(jìn)程肋殴,特別是服務(wù)器進(jìn)程往往在請(qǐng)求到來(lái)時(shí)生成子進(jìn)程處理請(qǐng)求。如果父進(jìn)程不等待子進(jìn)程結(jié)束坦弟,子進(jìn)程將成為僵尸進(jìn)程(zombie)從而占用系統(tǒng)資源护锤。
    如果父進(jìn)程等待子進(jìn)程結(jié)束,將增加父進(jìn)程的負(fù)擔(dān)酿傍,影響服務(wù)器進(jìn)程的并發(fā)性能烙懦。在Linux下可以簡(jiǎn)單地將SIGCHLD信號(hào)的操作設(shè)為SIG_IGN來(lái)解決這一問題。

示例: signal(SIGCHLD,SIG_IGN)// signal函數(shù)的使用
這樣赤炒,內(nèi)核在子進(jìn)程結(jié)束時(shí)不會(huì)產(chǎn)生僵死進(jìn)程氯析。

7.3.2日志信息及其管理
1:日志信息基本概念

為了告訴系統(tǒng)管理員守護(hù)進(jìn)程的運(yùn)行情況,守護(hù)進(jìn)程需要輸出特定信息莺褒,而守護(hù)進(jìn)程又不能把信息輸出到某個(gè)終端掩缓,因此,守護(hù)一般采用日志信息的方式輸出遵岩。

2:建立與日志守候進(jìn)程聯(lián)系

在進(jìn)程中你辣,調(diào)用函數(shù)openlog()將與日志守護(hù)進(jìn)程建立聯(lián)系,也就是說,如果需要寫日志信息,一般情況下绢记,都需要顯示調(diào)用此函數(shù)扁达,告訴日志守護(hù)進(jìn)程當(dāng)前進(jìn)程將寫日志;

extern void openlog(__const char *_ident,int_option,int _facility)

第一個(gè)參數(shù):要向每個(gè)消息加入字符串蠢熄,一般可設(shè)置為當(dāng)前進(jìn)程名

第二個(gè)參數(shù):用來(lái)描述一打開選項(xiàng)

第三個(gè)參數(shù):消息的類型跪解,決定將消息寫入到那個(gè)日志文件中。

如果在關(guān)閉與日志守護(hù)進(jìn)程的聯(lián)系签孔,可以調(diào)用colselog函數(shù)
extern void closelog(void)

3: 寫日志信息

syslog()將產(chǎn)生一條日志信息叉讥,然后由日志守護(hù)進(jìn)程將其發(fā)布到個(gè)日志文件中,該函數(shù)聲明:

extern void syslog(int _pri ,__const char *_fmt,...);

第一個(gè)參數(shù)決定日志類別.

第二個(gè)參數(shù)為日志輸出格式

7.3.3守候進(jìn)程應(yīng)用示例

/*
 ============================================================================
 Name        : Daemon_exp.c
 Author      : james
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/syslog.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>


int init_daemon(const char *pname,int facility){
    int pid;
    int i;
    signal(SIGTTOU,SIG_IGN);//處理可能的終端信號(hào)
    signal(SIGTTIN,SIG_IGN);
    signal(SIGTSTP,SIG_IGN);
    signal(SIGHUP,SIG_IGN);

    if(pid == fork()){// 創(chuàng)建子進(jìn)程饥追,父進(jìn)程退出
        exit(EXIT_SUCCESS);
    }else if(pid < 0){
        perror("fork");
        exit(EXIT_FAILURE);
    }

    setsid();// 設(shè)置新會(huì)話組長(zhǎng)图仓,新進(jìn)程組長(zhǎng),脫離終端
    if(pid == fork()){// 創(chuàng)建新進(jìn)程但绕,子進(jìn)程不能再申請(qǐng)終端
        exit(EXIT_SUCCESS);
    }else if(pid < 0){
        perror("fork");
        exit(EXIT_FAILURE);
    }

    for(i = 0;i < NOFILE;++i)// 關(guān)閉父進(jìn)程的文件描述符
        close(i);
    open("/dev/null",O_RDONLY);// 對(duì)標(biāo)準(zhǔn)輸入輸入全部重定向到/dev/null
    open("/dev/null",O_RDWR);// 因?yàn)橄惹瓣P(guān)閉了所有的文件描述符救崔,新開的值為0,1捏顺,2
    open("/dev/null",O_RDWR);
    chdir("/tmp");// 修改主目錄
    umask(0);//重新設(shè)置文件掩碼
    signal(SIGCHLD,SIG_IGN);// 處理子進(jìn)程退出
    openlog(pname,LOG_PID,facility);//與守候進(jìn)程簡(jiǎn)歷聯(lián)系六孵,加上進(jìn)程號(hào),文件名
    

    return 1;

}

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

    FILE *fd;
    time_t ticks;
    init_daemon(argv[0],LOG_KERN);
    while(1){
        sleep(1);
        ticks = time(NULL);
        syslog(LOG_INFO,"%s",asctime(localtime(&ticks)));
    }

    return EXIT_SUCCESS;
}
7.3.4:孤兒進(jìn)程與僵死進(jìn)程

孤兒進(jìn)程:因父進(jìn)程先退出而導(dǎo)致的一個(gè)子進(jìn)程被init進(jìn)程收養(yǎng)的為孤兒進(jìn)程幅骄。

/*
 ============================================================================
 Name        : orphan_p.c
 Author      : james
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
    pid_t pid;
    
    if((pid =  fork()) == -1)
        perror("fork");
    else if(pid == 0){
        while(1){
            printf("pid = %d,ppid = %d\n",getpid(),getppid());
            sleep(2);
            printf("pid = %d,ppid = %d\n",getpid(),getppid());
        }
    }
    else
        exit(0);
}


僵死進(jìn)程:而已經(jīng)退出但還沒有回收資源的進(jìn)程為僵死進(jìn)程劫窒。

案例示例:


/*
 * dead_p.c
 *
 *  Created on: Mar 7, 2016
 *      Author: james
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(){
    pid_t pid ;

    if((pid = fork()) == -1){
        perror("fork");
        exit(EXIT_FAILURE);
    }else if(pid == 0){
        printf("child_pid pid = %d\n",getpid());
        exit(0);
    }
    sleep(3);
    system("ps");
    exit(0);

}



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拆座,隨后出現(xiàn)的幾起案子主巍,更是在濱河造成了極大的恐慌,老刑警劉巖挪凑,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孕索,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡岖赋,警方通過查閱死者的電腦和手機(jī)檬果,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)唐断,“玉大人,你說我怎么就攤上這事杭抠×掣剩” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵偏灿,是天一觀的道長(zhǎng)丹诀。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么铆遭? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任硝桩,我火速辦了婚禮,結(jié)果婚禮上枚荣,老公的妹妹穿的比我還像新娘碗脊。我一直安慰自己,他們只是感情好橄妆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布衙伶。 她就那樣靜靜地躺著,像睡著了一般害碾。 火紅的嫁衣襯著肌膚如雪矢劲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天慌随,我揣著相機(jī)與錄音芬沉,去河邊找鬼。 笑死阁猜,一個(gè)胖子當(dāng)著我的面吹牛花嘶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹦漠,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼椭员,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了笛园?” 一聲冷哼從身側(cè)響起隘击,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎研铆,沒想到半個(gè)月后埋同,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棵红,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年凶赁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逆甜。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虱肄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出交煞,到底是詐尸還是另有隱情咏窿,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布素征,位于F島的核電站集嵌,受9級(jí)特大地震影響萝挤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜根欧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一怜珍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凤粗,春花似錦酥泛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至亭罪,卻和暖如春瘦馍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背应役。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工情组, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箩祥。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓院崇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親袍祖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子底瓣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容