进程管理1
1、进程基础(进程组成结构)
程序的执行实例被称为进程
程序的执行实例被称为进程(process)。本书的每一页几乎都会使用这一术语。某些操作系统用任务表示正被执行的程序。
每个linux进程都一定有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一非负整数。
进程包含PCB(进程控制块)、程序以及程序所操纵的数据结构集,可分为“代码段”、“数据段”和“堆栈段” 进程状态
运行状态R(TASK_RUNNING)
可中断睡眠状态S(TASK_INTERRUPTIBLE)
不可中断睡眠状态D(TASK_UNINTERRUPTIBLE)
暂停状态T(TASK_STOPPED或TASK_TRACED)
僵死状态Z(TASK_ZOMBIE)
退出状态X(TASK_DEAD)
init进程绝不会终止。
父进程与子进程
子进程得到的是除了代码段是与父进程共享的意外,其他所有的都是得到父进程的一个副本,子进程的所有资源都继承父进程,得到父进程资源的副本,既然为副本,也就是说,二者并不共享地址空间。,两个是单独的进程,继承了以后二者就没有什么关联了,子进程单独运行。
实例:
父进程中返回子进程ID
子进程中返回0
读时共享,写时复制
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void Write()//父进程,写数据
{
char buf[32] = "hello sadsadsaworld!";
int fd = open("hello.txt",O_CREAT|O_EXCL|O_RDWR,S_IRWXU);
if(-1 == fd)
{
perror("Write open");
exit(1);
}
int ret = write(fd,buf,strlen(buf));
if(-1 == ret)
{
perror("write");
exit(1);
}
close(fd);
}
void Read()//子进程,读数据
{
char buf[32] = {0};
int fd = open("hello.txt", O_RDONLY);
if(-1 == fd)
{
perror("Read open");
exit(1);
}
int ret = read(fd,buf,sizeof(buf));
if(-1 == ret)
{
perror("read");
exit(1);
}
printf("child buf :%s\n",buf);
close(fd);
}
int main()
{
pid_t pid;
pid = fork();
if(-1 == pid)
{
perror("fork");
exit(1);
}
else if(0 == pid)
{
sleep(1);
Read();
}
else
{
Write();
sleep(1);
}
return 0;
}
僵尸进程
僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源
孤儿进程
子进程是通过父进程创建的,子进程再创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。当一个父进程由于正常完成工作而退出或由于其他情况被终止,它的一个或多个子进程却还在运行,那么那些子进程将成为孤儿进程。为避免孤儿进程退出时无法释放所占用的资源而僵死,进程号为1的init进程将会接受这些孤儿进程,这一过程也被称为“收养”
fork注意事项
用fork创建子进程后执行的是和父进程相同的程序
fork系统调用之后,父子进程将交替执行。
如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。(注:任何一个进程都必须有父进程)
如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵进程。
exec
子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的
用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建
新进程,所以调用exec前后该进程的id并未改变。