linux进程运行队列,Linux进程调度中队列的使用
Linux内核中大量使用了队列,这里仅列举它在进程调度中的几处应用。Linux内核中的队列是以双链表的形式连接起来的,include/linux/list.h中定义了队列并提供了一些接口,详细的介绍可以参考**[1]**中的附录。
Linux中的进程有如下几个主要状态:
进程状态
说明
TASK_RUNNING
进程正在运行或将要被运行。
TASK_INTERRUPTIBLE
进程正在睡眠,等待某个条件的完成。
TASK_UNINTERRUPTIBLE
深度睡眠,不会被信号打扰。
TASK_STOPPED
进程运行被停止。
TASK_TRACED
进程被调试程序停止,被另一个进程跟踪。
两个额外的状态是EXIT_ZOMBIE和EXIT_DEAD,表示进程处于僵死状态还是真正死亡。处于僵死状态的进程会等待其父进程的收养(否则就会被init进程收养),而真正死亡的进程会被直接删除。
状态为TASK_RUNNING的进程都会被放入运行队列(runqueue)中,这是通过task_struct(定义在include/linux/sched.h)中的run_list成员来链接的。不过,为了让内核每次都能选取优先级最合适的进程,Linux为每个优先级构建了一个queue。这是通过struct prio_array来实现的,struct prio_array的定义在kernel/sched.c,大致如下:
struct prio_array
int nr_active;
unsigned long bitmap[BITMAP_SIZE];
struct list_head queue[MAX_PRIO];
};
queue成员就是队列数组。每个CPU有各自的runqueue,每一个runqueue又有包含两个prio_array,一个是活动队列,一个是时间片耗尽的队列。当运行队列空时,内核便会交换两个队列的指针,原来的耗尽队列就成了新的活动队列!这和prio_array中的bitmap是决定调度算法为O(1)的关键。
状态为TASK_STOPPED,EXIT_ZOMBIE或EXIT_DEAD的进程不会被放入专门的队列中,它们直接通过pid或者通过父进程的孩子队列来访问。
TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE状态的进程会被放入等待队列。不同的是,每个等待事件都会有一个等待队列,该队列中的进程等待同一事件的完成。(“事件”一个动态的过程,不好通过具体的结构来定义一个“事件”。这里等待一个事件就是查看某个条件是否为真,比如某个标志变量是否为真。)wait_queue_head_t的定义在include/linux/wait.h中,如下:
typedef struct _ _wait_queue_head {
spinlock_t lock;
struct list_head task_list;
}wait_queue_head_t;
wait_queue_t的定义如下:
typedef struct _ _wait_queue {
unsigned int flags;
struct task_struct * task;
wait_queue_func_t func;
struct list_head task_list;
}wait_queue_t;
进入等待状态的接口有两类:
prepare_to_wait*()/finish_wait()
wait_event*()
其实wait_event*()内部也是调用prepare_to_wait*(),把它放入一个循环中。而且wait_event*()在事件完成时会自动调用finish_wait()。决定使用哪个要看情况而定。(sleep_on*()是遗弃的接口,现在已经不再使用,虽然还支持。)等待队列中的进程有两种,一种是exclusive的进程,另一种是nonexclusive的进程。所谓exclusive是指唤醒的进程等待的资源是互斥的,每次只唤醒一个(唤醒多个也可以,不过最后还是只有一个会被唤醒,其余的又被重新添加到等待队列中,这样效率会大打折扣)。一般,等待函数会把进程设为nonexclusive和uninterruptible,带“interruptible”的会专门指定状态为interruptible;而带“timeout”的会在超时后退出,因为它会调用schedule_timeout();带“exclusive”的则会把进程设为exclusive。
唤醒的接口虽然只有wake_up*(),但它内部也分成好几种。带“interruptible”的唤醒函数只会唤醒状态是TASK_INTERRUPTIBLE的进程,而不带的则会唤醒TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程;所有唤醒函数都会把等待同一事件的nonexclusive进程全部唤醒,或者把其中一个exclusive的进程唤醒;而带“nr”的则会唤醒指定个数的exclusive的进程,带“all”的会把全部exclusive进程唤醒。带“sync”会忽略优先级的检查,高优先级的进程可能会被延迟。最后,持有自旋锁时只能调用wait_up_locked()。
进程管理是Linux内核中最关键的部分,它的性能几乎直接决定着内核的好坏,其中使用的一些设计和算法非常复杂。这里仅仅是介绍了队列在其中的使用情况,更深入的探索还有待继续去探索。
参考资料
Linux Kernel Development, Second Edition, Robert Love, Sam Publishing.
Understanding the Linux Kernel, 3rd Edition, Daniel P. Bovet, Marco Cesati, O’Reilly.
The Linux Kernel Primer: A Top-Down Approach for x86 and PowerPC Architectures, Claudia Salzberg Rodriguez, Gordon Fischer, Steven Smolski, Prentice Hall PTR.
linux进程运行队列,Linux进程调度中队列的使用相关推荐
- linux进程管理机制,linux进程管理,linux进程管理机制
linux进程管理,linux进程管理机制 一.基本介绍 1.在 LINUX 中,每个执行的程序(代码)都称为一个进程.每一个进程都分配一个 ID 号 2.每一个进程,都会对应一个父进程,而这个父进程 ...
- msgget();msgsnd();msgrcv();msgctl(); 消息队列 Linux进程间的通信方式之消息队列
Linux进程间的通信方式 ----消息队列. 消息队列和共享内存类似 消息队列它允许一个或多个进程向它写消息,一个或多个进程向它写读消息. 消息队列存在于系统内核中,消息的数量受系统限制. 我们来看 ...
- Linux进程通信之System V消息队列
System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...
- linux 进程 结构体,Linux中进程控制块PCB-------task_struct结构体结构
Linux中task_struct用来控制管理进程,结构如下: struct task_struct { //说明了该进程是否可以执行,还是可中断等信息 volatile long state; // ...
- python做Linux进程运行,Python实现在Linux系统下更改当前进程运行用户
在上一篇文章中,我们讲了如何在linux上用python写一个守护进程.主要原理是利用linux的fork函数来创建一个进程,然后退出父进程运行,生成的子进程就会成为一个守护进程.细心观察的可能会发现 ...
- linux 进程与锁,linux 中的进程与锁
############################################################################### #################### ...
- 内网linux服务器安装运行环境,linux下如何在内网中安装docker_网站服务器运行维护...
docker的镜像和仓库是什么_网站服务器运行维护 docker镜像就像是一个linux的文件系统,这个文件系统里面包含了可以运行在linux内核的程序以及相应的数据.仓库是集中存储镜像的地方. 一. ...
- Linux进程管理(4):进程调度
进程调度的本质是让进程更好地分时复用处理器资源.概况地说,进程调度包括调度策略和进程切换二个重要话题. 一.几个重要概念 1)时间片/优先级/抢占调度 所有的调度器都是围绕这3个概念进程设计,调度器之 ...
- Linux进程实践(1) --Linux进程编程概述
进程 VS. 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...
最新文章
- Linux编译mybatis,使用mybatis assembly插件打成tar包,在linux系统中运行服务-Go语言中文社区...
- html没有css还有用吗,如果css足够强大了,你还会用编程的方式实现去实现css已有的功能吗?_html/css_WEB-ITnose...
- javascript里你绝对用的上的字符分割函数--原创
- 扫描器scanner的源代码
- 闭包/Block当成函数参数实现回调
- 要求将数组中的0项去掉,将不为0的值存入一个新的数组,
- spring MVC中页面添加锚点
- linux alsa声卡命令,Linux ALSA声卡驱动之一:ALSA架构简介
- 编辑距离 dp_使用动态编程(DP)编辑距离
- 【Kafka】kafka console received unknown topic or partition error listOffset request
- jquery获取加载的html内容,jquery 获取ajax加载的html中部分内容
- 年仅 5 岁的 Rust 如何成为最受欢迎的编程语言?
- win10 基础之上安装 Linux-Manjaro-Deepin 连夜采坑,快速整理下
- 关于管理的十个经典故事
- Matable实现利用互相关函数求相位差
- 解决git clone出现“error: RPC failed; result= 18,HTTP code = 20018. 00 KiB/s”报错的五个网址(个人用)
- 计算机的输入法如何使用简短描述,应用电脑(1)第一章 计算机组成与中文输入法...
- linux运行魔力宝贝,魔力宝贝私服架设详细简易教程
- 大数据难学吗?如何学习大数据?(附学习路线)
- 防汛可视化:雨季来临,如何做好防汛措施?
热门文章
- ble 连接成功后找不到服务_闷声发大财的BLE芯片龙头
- java参数注解pam_吃透Java基础十:注解
- java保存登录信息_java – 保存登录详细信息(首选项)android
- UC浏览器电脑版怎么开启免费WiFi
- QQ浏览器怎么把文件添加到私密空间 怎么使用私密空间
- MySQL建表字段长度的限制、汉字和字母占字节数
- java实现 XSS攻击防护
- java实现简单二叉树
- 云服务器centos怎么还原系统还原,云服务器centos怎么还原系统还原
- android设置错误页面,Android ViewPager设置当前项目/页面时抛出IndexOutOfBounds异常