linux基础——进程的退出及资源回收

文章目录

  • 进程的退出
    • returen 和 exit
    • 代码示例
    • 注册进程结束调用函数
      • 代码示例(on_exit):
      • atexit
      • 代码示例(atexit)
  • 进程资源的回收
    • 代码示例
    • wait回收进程资源
      • 代码示例
    • waitpid
      • 代码示例
  • 给指定进程发送信号(kill)
  • 僵尸进程
    • 代码示例
  • 在进程的虚拟地址空间加载新的映像
    • 代码示例
  • 使用system启动新的可执行程序
    • 代码示例


进程的退出

returen 和 exit

return只是函数的返回,而exit却是进程的结束。

void exit(int status);

#include 
void exit(int status);
功能:终止进程
参数:
status:退出状态码。status&0377的值给父进程。
返回值:
永远不返回。

代码示例

  • test.c
#include 
#include 
int main(void){
     
	getchar();
	exit(-1);
}

  • 执行结果
    在这里插入图片描述

注册进程结束调用函数

在进程结束前,可以注册一些函数给进程,在进程结束时会自动调用这些被注册的函数。
on_exit(3)

#include 

int on_exit(void (*function)(int , void *), void *arg);

功能:注册一个函数给进程,在进程终止的时候调用该函数
参数:
function:指定退出函数的名字
void (*function)(int , void *)
arg:指定退出函数的第二个参数
返回值:
0    成功
非0   错误

代码示例(on_exit):

  • on_exit.c
#include 
#include 
void doit(int n,void *arg){
     
	printf("n=%d\targ:%s\n",\
		n,(char *)arg);
	return;
}

int main(void){
     
	//向进程注册退出函数
	on_exit(doit,"beijing");
	getchar();
	exit(3);
}

  • 执行结果
    linux基础——进程的退出及资源回收_第1张图片

atexit

atexit(3)

#include 
int atexit(void (*function)(void));
功能:注册一个函数给进程,在进程终止的时候调用该函数
参数:
function:指定了要注册的函数的名字
返回值:
0    成功
非0   错误

代码示例(atexit)

  • atexit.c
#include 
#include 

//注册给进程的退出函数
void doit(void){
     
	printf("hahha....\n");
	return;
}

int main(void){
     
	//向进程注册一个退出处理函数
	atexit(doit);
	getchar();
	return 0;
}

  • 执行结果
    linux基础——进程的退出及资源回收_第2张图片

进程资源的回收

在进程退出后,父进程会回收子进程的资源。
使用wait(2)、waitpid(2)系统调用回收子进程的资源。
如果父进程早于子进程结束,那么父进程的子进程的父亲就改变成为init进程,这种进程被成为孤儿进程。

代码示例

  • lonely.c
#include 
#include 
#include 

int main(void){
     
	pid_t pid;
	//创建子进程
	pid=fork();
	if(pid==-1){
     
		perror("fork");
		return 1;
	}
	if(pid==0){
     //子进程的代码
		sleep(5);
		printf("child...\n");
		//getchar();
		exit(0);
	}else{
     //父进程的代码
		printf("parent...\n");
		exit(0);
	}
	return 0;
}

  • 执行结果
    在这里插入图片描述

wait回收进程资源

#include 
#include 
pid_t wait(int *status);
功能:等待进程改变状态。
参数:
status:退出状态码的地址。子进程的退出状态存放在这块地址空间里。可以使用一些宏检测退出原因。
WIFEXITED(status)  如果正常死亡,返回真
WEXITSTATUS(status)  返回子进程的退出状态和0377的与,那个值。
WIFSIGNALED(status) 如果子进程被信号终止,返回真
WTERMSIG(status)  检测被几号信号终止。只有上个宏为真的时候,才使用。

返回值:
-1   错误
返回终止的子进程的pid

代码示例

  • wait.c
#include 
#include 
#include 
#include 
#include 
int main(void){
     
	pid_t pid;
	int s;
	//创建子进程
	pid=fork();
	if(pid==-1){
     
		perror("fork");
		return 1;
	}
	if(pid==0){
     
		printf("child pid=%d\n",\
			getpid());
		//sleep(5);
		getchar();
		exit(-1);
	}else{
     
		//等待子进程的结束
		wait(&s);
		if(WIFEXITED(s)){
     
			//子进程正常终止
			printf("status:%d\n",					WEXITSTATUS(s));
		}
		//检测子进程是否被信号终止
		if(WIFSIGNALED(s)){
     
			//输出终止子进程的信号编号
			printf("signum :%d\n",\
				WTERMSIG(s));
		}
		printf("parent...\n");
	}
	return 0;
}

  • 执行结果
    linux基础——进程的退出及资源回收_第3张图片

waitpid

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

功能:等待进程改变状态。
参数:
pid:
< -1: pid取绝对值,如果子进程的组id等于这个绝对值,那么这个子进程就被等待。
-1:等待任意子进程
0:等待和当前进程有同一个组id的子进程
> 0   等待子进程的pid是pid参数的子进程。
status:同wait(2)参数的使用
options:
WNOHANG:非阻塞回收。
0    阻塞回收
返回值:
-1   错误  
0   没有子进程退出
回收的子进程的pid

代码示例

  • waitpid.c
#include 
#include 
#include 
#include 
#include 
int main(void){
     
	pid_t pid;
	int s;
	//创建子进程
	pid=fork();
	if(pid==-1){
     
		perror("fork");
		return 1;
	}
	if(pid==0){
     
		printf("child pid=%d\n",\
			getpid());
		//sleep(5);
		getchar();
		exit(-1);
	}else{
     
		//非阻塞等待子进程的结束
		waitpid(-1,&s,WNOHANG);
		if(WIFEXITED(s)){
     
			//子进程正常终止
			printf("status:%d\n",					WEXITSTATUS(s));
		}
		//检测子进程是否被信号终止
		if(WIFSIGNALED(s)){
     
			//输出终止子进程的信号编号
			printf("signum :%d\n",\
				WTERMSIG(s));
		}
		printf("parent...\n");
	}
	return 0;
}

  • 执行结果
    linux基础——进程的退出及资源回收_第4张图片

给指定进程发送信号(kill)

kill -[信号编号] [进程的pid]

僵尸进程

子进程已经终止,但是父进程还没有回收子进程的资源,这时候的子进程处于僵尸状态,成为僵尸进程。

代码示例

  • zombile.c
#include 
#include 
#include 
#include 
#include 
int main(void){
     
	pid_t pid;
	pid=fork();
	if(pid==-1){
     
		perror("fork");
		return 1;
	}
	if(pid==0){
     
		exit(0);
	}else{
     
		sleep(20);
		wait(NULL);
	}
	return 0;
}

在进程的虚拟地址空间加载新的映像

在子进程的虚拟地址空间加载新的影像,需要使用系统提供的一个家族的函数。

execl(3)

#include 
extern char **environ;
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 *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const   char  *file,  char *const argv[],
                  char *const envp[]);

execve(2)

#include 
int  execve(const  char  *filename, char *const argv[],\
                  char *const envp[]);
相同的exec
l list   
v vector
p PATH    
e 环境变量
返回值:
成功调用永远不返回
-1  错误   errno被设置

代码示例

  • exec.c
#include 
#include 
#include 
#include 
char *const ps_argv[]={
     "ps","-o","pid,ppid,pgrp,comm",NULL};

int main(void){
     
	pid_t pid;
	
	//创建子进程
	pid=fork();
	if(pid ==-1){
     
		perror("fork");
		return 1;
	}
	if(pid==0){
     
		//加载新映像
		//execl("/bin/ps","ps","-o",\
		"pid,ppid,pgrp,comm",NULL);
	
		//execlp("ps","ps","-o",\
		"pid,ppid,pgrp,comm",NULL);
		execvp("ps",ps_argv);
	}else{
     
		wait(NULL);
	}
	return 0;
}

  • 执行结果:
    linux基础——进程的退出及资源回收_第5张图片

使用system启动新的可执行程序

#include 
int system(const char *command);
功能:执行一个shell命令
参数:
command:可执行命令
返回值:
-1  错误
返回command的退出状态码。

代码示例

  • system.c
#include 
#include 
#include 
#include 
#include 

int main(void){
     
	pid_t pid;
	pid=fork();
	if(pid==-1){
     
		return 1;
	}
	if(pid==0){
     
		execl("./myt","myt",NULL);
		//system("myt");
		exit(0);
	}else{
     
		wait(NULL);
	}
	return 0;
}

  • 执行结果
    linux基础——进程的退出及资源回收_第6张图片

你可能感兴趣的:(Linux基础,C语言基础)