1. 程式人生 > >Linux學習記錄--程序控制相關係統呼叫

Linux學習記錄--程序控制相關係統呼叫

系統呼叫:程序控制

fork系統呼叫

函式作用:建立一個子程序

形式:pid_tfork(void);

             pid_t vfork(void);

說明:    使用vfork創子程序時,不會程序父程序的上下文

返回值:[返回值=-1]子程序建立失敗

                 [返回值=0]子程序建立成功

                 [返回值>0]對父程序返回子程序PID

#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
intmain() {
	pid_t id = fork();
	if (id < 0) {
		perror("子程序建立失敗!");
	} else {
		if (id == 0) {
			printf("子程序工作:PID=%d,PPID=%d\n", getpid(), getppid());
		}else
		{
			printf("父程序工作:PID=%d,PPID=%d,子程序PID=%d\n", getpid(), getppid(),id);
			sleep(5)
		}
	}
}

控制檯輸出

父程序工作:PID=3173,PPID=2432,子程序PID=3176

子程序工作:PID=3176,PPID=3173

exit系統呼叫

函式作用:終止發出呼叫的程序

形式:voidexit(int status);

說明 

1.      exit返回資訊可由wait系統函式獲得

2.      如果父程序先退出子程序的關係被轉到init程序下

#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
intmain() {
	pid_t id = fork();
	if (id < 0) {
		perror("子程序建立失敗!");
	} else {
		if (id == 0) {
			printf("子程序工作:PID=%d,PPID=%d\n", getpid(), getppid());
			sleep(20);
			printf("此時子程序:PID=%d,PPID=%d\n", getpid(), getppid());
		}else
		{
			printf("父程序工作:PID=%d,PPID=%d,子程序PID=%d\n", getpid(), getppid(),id);
			sleep(5);
			exit(3);
		}
	}
	return 0;
}

控制檯輸出

父程序工作:PID=3068,PPID=2432,子程序PID=3071

子程序工作:PID=3071,PPID=3068

此時子程序:PID=3071,PPID=1

wait系統呼叫

函式作用:父程序與子程序同步,父程序呼叫後。進入睡眠狀態,直到子程序結束或者父程序在被其他程序終止,

形式:pid_twait(int *status)

             pid_t waitpid(pid_t pid ,int *status,int option)

引數:status:exit是設定的程式碼

            pid:程序號

            option: WNOHANG|WUNTRACED

WNOHANG:,即使沒有子程序退出,它也會立即返回,不會像wait那樣永遠等下去.
WUNTRACED:子程序進入暫停則馬上返回,但結束狀態不予以理會.

返回值:如果成功等待子程序結束,則返回子程序PID。後者為-1

用來檢查子程序返回狀態的巨集

WIFEXITED這個巨集用來指出子程序是否為正常退出的,如果是,它會返回一個非零值.

WEXITSTATUS當WIFEXITED返回非零值時,我們可以用這個巨集來提取子程序的返回值

wait函式使用

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

intmain() {
	pid_t cid;
	cid = fork();
	if (cid < 0) {
		perror("子程序建立失敗!");
	} else {
		if (cid == 0) {
			printf("子程序工作\n");
			printf("子程序PID=%d,PPID=%d\n", getpid(),getppid());
			//sleep(20); //1

		} else {
			//wait(NULL);//2
			//sleep(20);//3
			printf("父程序工作\n");
			printf("父程序PID=%d,PPID=%d\n", getpid(),getppid());
		}
	}
	return 0;
}

針對上述程式碼作以下分析:

1.       當子程序退出時,如果父程序沒有wait進行回收資源,子程序就會一直變為殭屍程序(Z)直到父程序退出

作法:

開啟3處註釋後執行程式,檢視程序狀態,如下

[[email protected]]# ps -C Process -o pid,ppid,stat,cmd

PID PPID STAT CMD

12233 11563S   /root/workspace/Process/Debug/Process

12238 12233Z    [Process] <defunct>

=>可以看到子程序此時的狀態時Z(殭屍程序)

控制檯輸出如下

子程序工作

子程序PID=12238,PPID=12233

20S…..

父程序工作

父程序PID=12233,PPID=11563

2.       使用wait進行程序同步,父程序直到子程序退出,wait才會結束等待

作法:

開啟12處註釋後執行程式,檢視程序狀態,如下

[[email protected] Debug8$] ps -C Process -o pid,ppid,stat,cmd

PID PPID STAT CMD

3425 2432 S   /root/workspace/Process/Debug/Process

3430 3425 S   /root/workspace/Process/Debug/Process

=>父程序與子程序都處於sleep狀態

控制檯輸出如下

子程序工作

子程序PID=3430,PPID=3425

20S…..

父程序工作

父程序PID=3425,PPID=2432

3. 使用wait進行程序同步,子程序退出後,父程序結束wait等待,同時清空子程序資訊,此時子程序不再是殭屍程序

作法:

開啟23處註釋後執行程式,檢視程序狀態,如下

[[email protected]]# ps -C Process -o pid,ppid,stat,cmd

  PID PPID STAT CMD

1250611563 S   /root/workspace/Process/Debug/Process

=>可以看到此時只有父程序資訊

控制檯輸出如下

子程序工作

子程序PID=12511,PPID=12506

20S…..

父程序工作

父程序PID=12506,PPID=11563

WEXITSTATUS與WIFEXITED巨集的使用

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

intmain() {
	pid_t cid;
	int pr, status;
	cid = fork();
	if (cid < 0) {
		perror("子程序建立失敗!");
	} else {
		if (cid == 0) {
			printf("子程序工作PID=%d,父程序PID=%d\n", getpid(),getppid());
			sleep(20);
			exit(3);
		} else {
			pr = wait(&status);
			if (WIFEXITED(status)) {
				printf("父程序工作PID=%d\n", getpid());
				printf("WAIT返回值=%d\n", pr);
				printf("子程序正常退出PID=%d\n", getpid());
				printf("WIFEXITED(status)=%d\n", WIFEXITED(status));
				printf("WEXITSTATUS(status)=%d\n", WEXITSTATUS(status));
			} else {
				printf("子程序異常退出PID=%d,訊號=%d\n", getpid(), status);
				printf("WAIT返回值=%d\n", pr);
			}
		}
	}
	return 0;
}

基於上面程式碼做出分析:

1.       子程序正常退出

控制檯輸出資訊如下:

子程序工作PID=12070,父程序PID=12069

(20S後…..)

父程序工作PID=12069

WAIT返回值=12070

子程序正常退出PID=12069

WIFEXITED(status)=1

WEXITSTATUS(status)=3

2.       子程序異常退出

作法:

執行程式,在子程序SLEEP期間,殺死子程序

[[email protected] Debug]# kill -9 11990

控制檯臺輸出如下

子程序工作PID=11990,父程序PID=11985

(kill -9 PID 殺死子程序)

子程序異常退出PID=11985,訊號=9

可以看出子程序正常退出時,status返回值是exit的退出值,子程序異常退出時status返回值訊號值

waitpid函式使用

waitpid的引數說明

引數pid的值有以下幾種型別:
pid>0時,只等待程序ID等於pid的子程序,不管其它已經有多少子程序執行結束退出了,只要指定的子程序還沒有結束,waitpid就會一直等下去.
pid=-1時,等待任何一個子程序退出,沒有任何限制,此時waitpid和wait的作用一模一樣.
pid=0時,等待同一個程序組中的任何子程序,如果子程序已經加入了別的程序組,waitpid不會對它做任何理睬.
pid<-1時,等待一個指定程序組中的任何子程序,這個程序組的ID等於pid的絕對值.


引數options的值有以下幾種型別:
如果使用了WNOHANG引數,即使沒有子程序退出,它也會立即返回,不會像wait那樣永遠等下去.
如果使用了WUNTRACED引數,則子程序進入暫停則馬上返回,但結束狀態不予以理會.
如果我們不想使用它們,也可以把options設為0,如:ret=waitpid(-1,NULL,0);

WNOHANG使用

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

int main() {
	pid_t cid;
	int pr, status;
	cid = fork();
	if (cid < 0) {
		perror("子程序建立失敗!");
	} else {
		if (cid == 0) {
			printf("子程序工作PID=%d\n", getpid());
			sleep(5);
			exit(3);
		} else {

			do{
				pr = waitpid(0,&status,WNOHANG);
				if(pr==0)
				{
				printf("沒有子程序退出,繼續執行..\n");
				sleep(1);
				}

			}while(pr==0);
			printf("子程序正常退出PID=%d\n", pr);

		}
	}
	return 0;
}

控制檯輸出

沒有子程序退出,繼續執行..

子程序工作PID=3632

沒有子程序退出,繼續執行..

沒有子程序退出,繼續執行..

沒有子程序退出,繼續執行..

沒有子程序退出,繼續執行..

子程序正常退出PID=3632

針對某一程序進行等待

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

intmain() {
	pid_t cid;
	int pr, status;
	cid = fork();
	if (cid < 0) {
		perror("子程序建立失敗!");
	} else {
		if (cid == 0) {
			printf("子程序工作PID=%d,PPID=%d\n", getpid(), getppid());
			sleep(20);
			exit(3);
		} else {
			pr = waitpid(cid, &status, 0);
			printf("父程序正常退出PID=%d\n", pr);
		}
	}
	return 0;
}

控制檯輸出

子程序工作PID=4257,PPID=4252

父程序正常退出PID=4257

WUNTRACED 使用

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

intmain() {
	pid_t cid;
	int pr, status;
	cid = fork();
	if (cid < 0) {
		perror("子程序建立失敗!");
	} else {
		if (cid == 0) {
			printf("子程序工作PID=%d,PPID=%d\n", getpid(), getppid());
			sleep(30);
			exit(3);
		} else {
			pr = waitpid(cid, &status, WUNTRACED);
			printf("父程序正常退出PID=%d,status=%d\n", pr,status);
		}
	}
	return 0;
}

作法:在子程序SLEEP時,通過SHELL命令停止子程序

[[email protected] ~ 6$] kill -STOP PID

控制檯輸出

子程序工作PID=4110,PPID=4108

(SLEEP期間,停止子程序)

父程序正常退出PID=4110,status=4991

在檢視程序狀態,發現此時父程序子程序都已經退出

[[email protected] Debug 13$] ps -C Process -opid,ppid,stat,cmd

 PID  PPID STAT CMD

exec系統呼叫

函式作用:以新程序代替原有程序,但PID保持不變

形式:

int execl(const char *path, const char*arg, ...);

int execlp(const char *file, const char*arg, ...);

int execle(const char *path, const char*arg, ..., char * const envp[]);

int execv(const char *path, char *constargv[]);

int execvp(const char *file, char *constargv[]);

int execve(const char *path, char *constargv[], char *const envp[]);

舉例:

exec1.c
#include<stdio.h>
#include<unistd.h>

intmain()
{
printf("這是第一個程序PID=%d\n",getpid());
execv("e2",NULL);
printf("asa");
return 0;
}

exec2.c
#include<stdio.h>
#include<unistd.h>

intmain()
{
printf("這是第二個程序PID=%d\n",getpid());
}


執行結果:

[[email protected] Process 9$] gcc -o e1 exec1.c

[[email protected] Process 10$] gcc -o e2 exec2.c

[[email protected] Process 11$] ./e1

這是第一個程序PID=3051

這是第二個程序PID=3051