目录
1.进程状态
进程状态就是task_struct内的一个整数
1.课本上的说法---名词提炼

2.运行&&阻塞&&挂起
CPU选择一个进程去运行,本质并不是选择这个进程的代码和数据去运行,选择一个进程特定的PCB去运行。
task_struct有个指针找到对应的代码和数据。
一个CPU,一个调度队列
struct struct*runqueue
一个数据节点既可属于a数据结构也可以属于b数据结构
PCB 全局链表 队列
调度算法---FIFO
CPU调度就是在这个队列中按照顺序依次选择一个task_struct来进行调度执行.
什么叫做进程的运行状态?
一个进程它持有cpu在那里跑的时候就是运行状态。
但是在当代计算机中,只要一个进程在调度队列中,我们就称这个进程叫做运行状态。
运行:进程在调度队列中,进程的状态都是running!
阻塞:等待某种设备或者资源就绪 键盘、显示器、网卡、磁盘、摄像头、话筒.....当我们scanf的时候,并不是等待用户输入,而是等待键盘硬件就绪(键盘上有按键被按下)
没有按下时我们称为键盘硬件不就绪,这样scanf就无法读取数据。
在等期间如果一直不就绪,进程不会被调度,就卡在那里不动了
OS要管理系统中的各种硬件资源,先描述,再组织!struct device
{
int id;
int vender;
int status;
void *data;
int type;
.....
struct device *next;
struct task_struct *wait_queue;
}
操作系统要管理底层的所有硬件,在开机的时候为我们每一个设备创建一个struct device的节点。把每一个设备连接起来,对应底层的硬件。操作系统对硬件做管理就转化成了对链表的增删查改。
操作系统除了运行队列还要有设备队列struct device *devices,对应的每一个设备都有自己的一个等待队列struct task_struct *wait_queue;
当一个设备没有活跃的时候,操作系统会认为无法执行,把这个进程从cpu上拿下来从运行队列中移走,把它的PCB链入到特定设备的等待队列中,不在运行队列中该进程就永远不会被调度了,这个进程就处于阻塞状态。
当键盘按下,属于硬件就绪了。操作系统作为硬件的管理者,硬件变化了,操作系统第一个知道。操作系统一旦知道,就转而去查看对应的就绪设备的对应节点,将状态设置为活跃。然后检查等待队列,发现指针不为空,就将其中状态设置为运行状态,将该进程重新链回运行队列。
进程状态的变化,表现之一,就是要在不同的队列中进行流动,本质都是数据结构的增删查改!
挂起:如果当前计算机内进程资源严重不足,操作系统中
有一些资源不会被立即访问,在磁盘中有个分区叫做swap交换分区。内存资源严重不足,将对应的代码和数据置换到磁盘的swap分区上,在内存只将PCB存下来,代码和数据唤出到磁盘上。此时这些进程的状态叫做阻塞挂起。
挂起 当操作系统内存吃紧时,操作系统做一些内存页面置换的算法。把不会调度的进程或者相关的磁盘块交换到磁盘上,这样的进程叫做阻塞挂起。挂到外设挂到磁盘
如果执行,操作系统唤入到内存中,继续被调度。
swap交换分区的唤入和唤出
进程阻塞挂起
运行挂起状态如果操作系统内部内存资源特别吃紧,阻塞挂起还是不够,操作系统可能会把运行队列末端的进程进入磁盘要调度的时候再拿出来,这种状态叫做运行挂起状态
理解内核链表的话题
struct list_head
{
struct list_head *next,*prev;
};
首先设置list_head节点,包含两个指针
特定的数据结构,链表的数据结构是不包含的任何数据,而是把链表的节点next、prev单独封装一个节点类型,而把这个类型作为新的目标属性的成员。
struct task_struct
{
int x;
int y;
int z;
list_head links;
...
}
地址依次增大
struct task_struct a;
&a==&a.x;
linux中next只会指向下一个内部的某个,不像正常双链表的指向下一个整体
如果想要访问其中任意一个该怎么办?
links;
&((struct task_struct*)0->links) 计算结构体成员相对0号地址的偏移量,找到该地址的位置
(struct task_struct*)(next_list-&((struct task_struct*)0->links))
next_list是links成员的实际地址(例如在内存中真实的指针值)。减去刚才计算出的偏移量 ,就得到结构体
task_struct的起始地址。最后将该地址强制转换为
struct task_struct *,即可通过成员指针访问整个结构体。在task_struct中有很多next、prev的节点组合,而各个task_struct再进行连接
所以一个数据节点既可属于a数据结构也可以属于b数据结构
PCB 全局链表 队列
3.linux的进程状态
Linux内核源代码怎么说
• 为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。
下面的状态在kernel源代码里定义:
/*
*The task state array is a strange "bitmap" of
*reasons to sleep. Thus "running" is zero, and
*you can test for combinations of others with
*simple bit tests.
*/
static const char *const task_state_array[] = {
"R (running)", /*0 */
"S (sleeping)", /*1 */
"D (disk sleep)", /*2 */
"T (stopped)", /*4 */
"t (tracing stop)", /*8 */
"X (dead)", /*16 */
"Z (zombie)", /*32 */
};
• R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
• S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。
• D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个 状态的进程通常会等待IO的结束。
• T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的 进程可以通过发送 SIGCONT 信号让进程继续运行。
• X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
[user1@iZ5waahoxw3q2bZ 26-4-22]$ cat myprocess.c
#include<stdio.h>
int main()
{
while(1)
{
printf("hello world!\n");
}
return 0;
}
[user1@iZ5waahoxw3q2bZ 26-4-22]$ gcc myprocess.c -o myprocess
[user1@iZ5waahoxw3q2bZ 26-4-22]$ ./myprocess
hello world!
hello world!
while :; do ps ajx | head -1 ; ps ajx | grep myprocess; sleep 1; done
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
20979 21003 21002 20979 pts/1 21002 S+ 1001 0:00 grep --color=auto myprocess
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
20928 21050 21050 20928 pts/0 21050 S+ 1001 0:00 ./myprocess
20979 21059 21058 20979 pts/1 21058 S+ 1001 0:00 grep --color=auto myprocess
