我们都知道进程信息被放到了PCB(task_struct)中,可以理解为进程属性的集合。
PCB中包含了进程的ID,时间片,pc指针,所有的寄存器,进程状态、优先级、I/O状态信息等等...有兴趣的可以去看看源码,也可以去看看这篇文章https://www.cnblogs.com/tongyan2/p/5544887.html
PCB是内核中很重要的一个数据结构,每一个在系统中运行的进程,都是以PCB的链表形式存在内核中,它管理起了OS的内核。
在OS中,弄明白进程的不同状态是很重要的,在内核中,有以下几种状态:
R(运行状态 running):R状态并不意味着运行中,也有可能在运行队列中。
S(可中断状态 sleeping):也叫做睡眠状态,意味着进程在等待事件完成。
D(不可中断状态 Disk sleep): 有时候也叫做不可中断睡眠状态,在这个状态的进程通常会等待IO的结束。
T(停止状态 stopped):可以通过SIGSTOP信号来暂停T进程,当然也可以通过信号来让进程继续运行。
X(死亡状态 dead): 这个状态只有一个返回状态,你不会在任务列表中看到这个进程。
运行状态(R):
我们用下面的代码来模拟一下R状态,
可以发现,这与我们的想法不一样? 这是为什么呢??
我们都知道在内存很快,当sleep函数的时候,OS会很快将它执行完,这时就由R -> S
僵尸状态(Z):
int main()
{
int time = 0;
int ret = fork();
if (ret < 0)
{
perror("fork fail\n");
exit(-1);
}
if (ret == 0)
{
// child
while(1)
{
cout << "我是子进程:pid:" << getpid() << " " << "ppid:" << getppid() << " " << ++time << endl;
sleep(1);
if(time == 10)
{
return 1;
}
}
}
else
{
// father
while(1)
{
cout << "我是父进程:pid:" << getpid() << " "<< "ppid:" << getppid() <<" " << ++time << endl;
sleep(1);
}
}
return 0;
}
我们可以发现,第10s的时候,由于子进程退出先于父进程退出,并且父进程没有读取到子进程的退出码,就会造成僵尸状态。
危害:这非常消耗资源,因为子进程的代码和数据,进程ID...都在PCB中,如果父进程没有读取退出状态代码,那么子进程会一直以终止状态保持在进程表中。
孤儿进程:
所谓孤儿进程,就是当父进程先于子进程退出,这时子进程就是孤儿进程,但当子进程退出变成Z的时候,会由1号进程来回收子进程。