Linux系统编程01

1 fork函数

1.1 fork函数用法简介

函数原型: pid_t fork(void)    pid_t是返回的一个标识,在不同的平台可能定义不一样,可以是int或者long类型等等,pid_t定义在 sys/types.h中

	pid_t pid = fork();
	if (pid == 0) {//子进程
	}
	if(pid>0){ //父进程,此时pid的值是子进程的id号

	}
	if(pid==-1){  //此时创建子进程失败

	}

fork创建进程失败的原因:进程数量超出限制或者内存空间不足

1.2 fork创建进程空间共享问题

使用fork创建的子进程在一开始除了pcb和父进程不一样,其余的空间遵循读时共享写时复制,文件描述符是共享

1.3 创建子进程导致的僵尸进程和孤儿进程的问题

僵尸进程:子进程先于父进程退出后,子进程的PCB需要其父进程释放,但是父进程并没有释放子进程的PCB,这样的子进程就称为僵尸进程,僵尸进程实际上是一个已经死掉的进程,但是仍然占用内存空间

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作,不会像僵尸进程那样占用ID,损害运行系统

解决僵尸进程的方法:

  • 杀死父进程,子进程的资源就会被init进程回收,但是一般父进程是一个服务器程序,不可能使用这种暴力的方式
  • 在父进程中使用wait或者waitpid函数,使用wait函数回收资源会导致父进程阻塞,合理的使用waitpid函数不会导致父进程阻塞
  • 使用信号处理,当子进程退出时会像父进程发送SIGCHLD信号,所以我们可以在程序一开始时就设置处理这种信号的方法,但是当有多个信号同时到来时可能会导致信号丢失的情况

2 wait函数和waitpid函数

2.1 绪论

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程

2.1 wait

该函数有三个功能:

  • 阻塞等待子进程退出
  • 回收子进程残留资源
  • 获取子进程结束状态(退出原因)。

wait一旦被调用,就会一直阻塞在这里,直到有一个子进程退出出现为止

函数原型:

pid_t wait(int *status);   //如果不关心程序退出的状态,可以传入NULL

成功:清理掉的子进程ID;失败:-1 (没有子进程)

使用wait函数传出参数status来保存进程的退出状态 (正常终止→退出值;异常终止→终止信号)。借助宏函数来进一步判断进程终止的具体原因,宏函数具体参考Linux中man命令

2.2 waitpid

函数原型:

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

//第一个参数
pid<-1  等待进程组号为pid绝对值的任何子进程
pid=-1  等待任何子进程,此时的waitpid()函数就退化成了普通的wait()函数。
pid=0   等待进程组号与目前进程相同的任何子进程,也就是说任何和调用waitpid()函数的进程在同一个进程组的进程。
pid>0   等待进程号为pid的子进程。

//第二个参数需要搭配具体的宏函数来获得其状态,如果不关心具体的状态则传入NULL

//第三个参数,其参数可以用 “|” 运算符连接起来使用。
WNOHANG  如果pid指定的子进程没有结束,则waitpid()函数立即返回0,而不是阻塞在这个函数上等待;如果结束了,则返回该子进程的进程号。
WUNTRACED	如果子进程进入暂停状态,则马上返回。

如果waitpid()函数执行成功,则返回子进程的进程号;如果有错误发生,则返回-1,并且将失败的原因存放在errno变量中。

失败的原因主要有:没有子进程(errno设置为ECHILD),调用被某个信号中断(errno设置为EINTR)或选项参数无效(errno设置为EINVAL)

waitpid(-1, status, 0)  退化等价与wait(status)

3 exec函数簇

参考博客:https://blog.csdn.net/amoscykl/article/details/80354052

发布了123 篇原创文章 · 获赞 31 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_40794602/article/details/104646846
今日推荐