exec函数族
exec系统调用:可以把当前进程替换为一个新进程,并转换到调用进程的内存空间
execl、execlp
举例子:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
int main(int argc,char *argv[]){
pid_t ret;
ret = fork();
if(ret == 0 ){
// execlp("ls","ls","-l","-h",NULL);
execl("../demo1025/sys-fork","./sys-fork",NULL);
perror("execlp error");
printf("i am child");
}
if(ret >0){
sleep(2);
printf("i am parent");}
if(-1 == ret ){
perror("error");
}
}
小问题:
my_execlp.c: 在函数‘main’中:
my_execlp.c:14: 警告:隐式声明与内建函数‘exit’不兼容
my_execlp.c:22: 警告:隐式声明与内建函数‘exit’不兼容
解决方式:手动添加函数声明void exit(int);
默认的隐式声明int exit(int);
孤儿进程
父进程结束了,而子进程依然存在,那么子进程成为了孤儿进程,由init进程接收。
僵尸进程
当一个子进程结束运行的时候,它与其父进程之间的关联还会保持到父进程也正常地结束运行或者父进程调用了wait才告终止,称之为僵尸进程。
回收子进程
wait
1、使父进程阻塞等待
2、返回结束的子进程的pid
3、通过status能够获取子进程结束的状态。
waitpid
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char *agrv[]){
pid_t pid_ret1,pid_ret2;
int i=0;
int status;
for(;i<5;i++){
pid_ret1 = fork();
if(pid_ret1 == 0){
printf("times = %d pid = %d\n",i,getpid());
break;
}
//pid_ret2 = wait(&status);
pid_ret2 = waitpid(-1,&status,WNOHANG);
printf("waitpid = %d\n",pid_ret2);
if(WIFEXITED(status)){
printf("returns the exit status of the child\n");
}
}
}
进程间通信IPC
四种:
管道pipe、fifo
特点:伪文件,内核当中的一个缓冲区
应用在有血缘关系的进程间。
本质上是一个队列,循环队列。
局限性:
1、一端充当读端,一端充当的写端
2、不能反复读取
3、双向半双工
pipe读和写的特点
写端:
1、所有读端全部关闭,异常终止
2、有读端,
管道已满 阻塞等待
未满,返回实际的字节数。
读端:
1、管道有数据,返回实际读到的字节数
2、管道无数据,
无写端 返回0
有写端 阻塞
练习:
子进程中实现ls 父进程中实现wc -l
#include <stdio.h>
#include <unistd.h>
void exit(int);
int main(int argc,char *agrv[]){
pid_t pid_ret1;
int i=0;
int fd[2];
char buff[]="hello";
char buff1[6];
int ret = pipe(fd);
if(-1 == ret)
{
perror("pipe failed");
exit(1);
}
pid_ret1 = fork();
if(-1 == pid_ret1){
perror("fork failed!");
exit(1);
}
//写端 ls
if(0 == pid_ret1){
close(fd[0]);
dup2(fd[1],STDOUT_FILENO);
//execlp
execlp("ls","ls",NULL);
close(fd[1]);
printf("child\n");
}
//读段 wc -l
if(pid_ret1 >0)
{
close(fd[1]);
sleep(1);
dup2(fd[0],STDIN_FILENO);
//重定向,将原本对标准输入操作重定向为fd[0]
printf("************");
execlp("wc","wc","-l",NULL);
//执行wc -l的功能,不再从标准输入读取,而是从fd[0]读取了
//注意:dup2必须先于execlp执行,否则没有重定向的时机了。
close(fd[0]);
printf("parent\n");
}
}
练习:
2个兄弟进程间实现ls |wc -l
父进程回收子进程ID