目录
一、进程创建
(一)进程创建过程
进程创建的一般过程:
(1)分配一个唯一的标识符,在内核中创建出task_struct;
(2)复制父进程的环境信息;
(3)给新进程分配资源(栈、堆等);
(4)拷贝父进程的地址空间内容;
(5)将进程放入就绪队列;
(二)进程创建函数——fork()
1、fork()函数
头文件:#include<unistd.h>
fork()函数:pid_t fork(void);
返回值:
父进程返回子进程的pid;
子进程返回0;
返回-1则出错;
2、简单的创建进程例子
(1)
从结果中可以看出,fork()创建出来的子进程是将父进程的信息进行了拷贝,并且继续接着父进程执行下去;
(2)
从结果中我们可以得到,子进程返回0,父进程返回子进程的pid;
(三)进程创建原理
从例(1)中可以看出,fork()创建出来的子进程实际上就是对父进程的一个拷贝;
一般来说,fork()出的子进程的虚拟地址空间是拷贝的父进程的虚拟地址空间,所以无论是代码还是数据又或是环境变量等信息都是与父进程相同的;
在映射到物理内存时,如果不对子进程的信息进行修改的话,是可以让子进程和父进程共享同一个物理内存中;如果需要对子进程信息进行修改的话,则会改变其物理内存的位置,我们称之为写时拷贝。写时拷贝会大大提高存储效率。
二、进程退出
进程退出有两种退出:
1、正常退出:exti()函数退出
2、异常退出:子进程被杀死,从而变成僵尸子进程;
三、回收僵尸子进程
(一)简单回收僵尸子进程函数——wait
当子进程非正常死亡时,为了避免内存泄漏,需要通过父进程将其回收,这里用到的函数就是wait函数;
(1)头文件:#include<sys/wait.h>
(2)函数:pid_t wait(int* status);
(3)返回值:成功返回子进程pid;错误返回-1;
(4)参数:
status:获得子进程死亡信息,有以下几个参数:
WIFEXITED:返回真,子进程正常退出;
WEXITSTATUS:在WIFEXITTED为真的前提下,获取子进程的退出状态信息;
WIFSINGALED:返回真说明子进程被信号打断;
wait()函数使用例子:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
#include<string.h>
#define ERR_EXIT(msg) \
do{ \
printf("[%s][%d] %s: %s\n", __FILE__, __LINE__, msg, strerror(errno)); \
exit(EXIT_FAILURE); \
} while(0)
int main()
{
pid_t pid;
if ((pid = fork()) == 0)
ERR_EXIT("fork");
if (pid == 0)
{
printf("child pid = %d\n", getpid()); //getpid()获取自己的进程pid
sleep(3);
exit(0);
}
else
{
int status;
pid_t ret;
if ((ret = wait(&status)) == -1)
ERR_EXIT("wait");
if (WIFEXITED(status)) //WIFEXITED返回真,子进程正常退出
{
printf("normal exit: %d\n", WEXITSTATUS(status)); //获取子进程退出状态信息
}
else if(WIFSIGNALED(status)) //如果为真,子进程被信号打断
{
printf("killed by kill cmd\n");
}
printf("ret = %d\n", ret);
while(1)
{
printf(".");
fflush(stdout);
sleep(1);
}
}
return 0;
}
(二)wait()函数进阶版——waitpid()函数
wait()函数能够回收僵尸子进程,但是并不能指定回收,而且如果没有回收到就会一直阻塞;而waitpid()函数功能更加强大,它能够指定回收僵尸子进程,并且没有回收到可以不阻塞;
(1)头文件:#include<sys/wait.h>
(2)函数:pid_t waitpid(pid_t pid, int* status, int options);
(3)返回值:成功返回子进程pid;错误返回-1;
(4)参数:
第一个参数pid,在这个参数中就可以控制想要回收的子进程:
>0:明确指定要回收的子进程
=0:回收和调用者进程在同一组的任何一个子进程
=-1:回收自己的任何一个子进程
<-1:|pid|进程组的任何一个子进程死亡,都能被回收
第二个参数和wait中的参数一样,都是获取子进程的死亡信息;
第三个参数options:该选项选择阻塞还是不阻塞
WNOHANG:如果调用这个函数时,有子进程是僵尸状态,回收并返回,如果没有,立即返回而不会阻塞