LINUX下子进程与防止僵尸进程(函数指针的使用)

本文深入探讨了进程管理的基础概念,包括父进程如何通过fork函数创建子进程,子进程的状态及其对僵尸进程的影响。此外,还详细介绍了如何利用wait、waitpid等函数解决僵尸进程问题,并通过信号处理函数实现更高效的过程控制。

父进程通过fork函数创建子进程,克隆fork函数之后的代码到子进程。父进程中fork返回子进程ID,子进程中返回0

 

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

int gval = 10;
int main(int argc,char *argv[])
{
    pid_t pid;
    int lval = 20;
    gval++,lval+=5;

    pid = fork();    //创建子进程
    if(pid == 0)	
		gval += 2,lval += 2; //子进程
	else
		gval -= 2,lval -= 2;//父进程

    if(pid == 0)
		printf("child proc:[%d,%d] \n",gval,lval);//子进程
	else	
		printf("parent proc:[%d,%d] \n",gval,lval);//父进程
	return 0;
}


僵尸进程,即父进程没有向子进程获取到exit或者return返回的值,因此在父进程结束之前,子进程为僵尸进程
如下程序:

 

 

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

int main(int argc,char argv[])
{
	pid_t pid = fork();

	if(pid == 0)
		puts("hi,i am a child process id!\n");
	else
	{
		printf("child process id:%d \n",pid);
		sleep(10);					//等待10s后结束父进程,结束前子进程属于僵尸进程
	}								//此时查看系统进程信息,子进程的ID存在

	if(pid == 0)
		puts("end child process\n");
	else
		puts("end parent process\n");

	return 0;						//此时再查看,子进程消失
}


父进程通过调用wait函数获取子进程返回值来结束僵尸进程,在子进程结束前,该函数阻塞
成功返回ID,失败返回-1
pid_t wait(int * statloc);
需要通过以下另个宏分离statloc参数
WIFEXITED:子进程是否正常退出,是则为1
WEXITSTATUS:子进程ID

 

 

 

 

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

int main(int argc,char argv[])
{
	int status;
	pid_t pid = fork();

	if(pid == 0)
		return 3; //子进程1返回值到操作系统
	else
	{
		printf("\n");
		printf("child pid:%d\n",pid);

		pid = fork();
		if(pid == 0)
			exit(7);//子进程2返回值到操作系统
		else
		{
			printf("child pid:%d\n",pid);
			wait(&status); //父进程获取子进程1的返回值,并彻底终止子进程,下同
			if(WIFEXITED(status))
				printf("child send one :%d\n",WEXITSTATUS(status));

			wait(&status);
			if(WIFEXITED(status))
				printf("child send two :%d\n",WEXITSTATUS(status));

			sleep(15); //在等待过程中,虽然父进程并未终止,但子进程已经终止
		}
	}
	return 0;
}


waitpid函数是对wait函数的改进,在子进程结束前它不会阻塞:
pid_t waitpid(pid_t pid,int* statloc,int options);
pid为等待终止的进程ID,
statloc同wait
option为常量WNOHANG,即没有终止的子进程也不会阻塞,而是return 0


信号处理signal函数
该函数作用:当父进程发现子进程终止时,请求操作系统调用特定的函数处理,即信号注册函数。

 

 

 

 

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

void timeout(int sig)
{
	if(sig == SIGALRM)
		puts("Time out\n");
	alarm(2);//每隔2s发出SIGALRM信号
}

void keycontrol(int sig)
{
	if(sig == SIGINT)
		puts("CTRL + C pressed \n");
}

int main(int argc,char argv[])
{
	int i;
	signal(SIGALRM,timeout); //当子进程超过alarm的两秒时间时,则发出一个事件,调用timeout函数
	signal(SIGINT,keycontrol);//当子进程被CTRL+C中止时,则调用keycontrol函数
	alarm(2);

	for(i=0;i<3;i++)
	{
		puts("wait...\n");
		sleep(100);//父进程结束前会不停输出Time out
	}
	return 0;
}


更稳定的sigaction函数,用法同signal

 

 

 

 

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

void read_childproc(int sig)
{
	int status;
	pid_t id = waitpid(-1,&status,WNOHANG);
	if(WIFEXITED(status))
	{
		printf("Remove process id:%d \n",id);
		printf("Child send:%d \n",WEXITSTATUS(status));
	}
}

int main(int argc,int *argv[])
{
	pid_t pid;
	struct sigaction act;
	act.sa_handler = read_childproc;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGCHLD,&act,0);

	pid = fork();
	if(pid == 0)
	{
		puts("Hi,I am a child process!\n");
		sleep(10);
		return 12;
	}
	else
	{
		printf("child process id:%d\n",pid);
		pid = fork();
		if(pid == 0)
		{
			puts("Hi,I am i child process\n");
			sleep(10);
			exit(24);
		}
		else
		{
			int i;
			printf("child process id is:%d\n",pid);
			for(i = 0;i<5;i++)
			{
				puts("wait...");
				sleep(5);
			}
		}
	}
	return 0;
}

函数指针的使用:

 

 

#include<stdio.h>

void cal(int a,int b)
{
	a+=2;
	b+=3;
	printf("modfied!\n");
	printf("a:%d b:%d\n",a,b);
}

void print(void (*func)(int,int),int x,int y)//第一个参数为函数指针,该指针要求所致函数参数为两个整型,返回值为void,固定格式type (*function)(type,type...)
{
	func(x,y);
}

int main(int argc,int argv[])
{
	print(cal,3,5);
	return 0;
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值