父进程通过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;
}