linux系统编程——进程管理——高级
2021/8/25 7:06:01
本文主要是介绍linux系统编程——进程管理——高级,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 进程调度
进程调度是内核子系统,用于将有限的处理器使用时间资源分配给各个进程,决定哪些进程可以运行及运行多久。
调度的目标:
*最大化cpu利用率
- 尽可能提高系统交互响应速度
- 让每个进程都能被运行
2. 调度分类
- 协同式:进程自己主动放弃运行,让其他进程运行
- 抢占式:调度程序决定何时停止一个进程运行,让不同进程继续运行
linux使用抢占式。
3. 时间片
时间片是cpu分配的基本单位。
时间片的长短设置值得考虑。
通常,若希望最大化系统吞吐量及整体性能,可以使用较大时间片(减少进程切换,享受时间局部性)。
若希望最佳交互性能,则使用非常小时间片。
注意,进程可能不会用完它的所有时间片,
如,进程被分配了100ms时间,可能运行20ms,然后阻塞等待资源。
调度程序会将其从可运行进程列表中移除,当资源可用,调度程序会唤醒进程。
然后进程继续运行,直到用完时间片剩余80ms,或再次阻塞等待资源。
4. 从进程角度看调度
进程分为:
- IO密集型:希望分配较长时间片,但不太在乎调度优先级
- cpu密集型:很在乎调度优先级,不太在乎时间片长度
linux调度程序会试图找到IO密集型程序,并提高优先级,并降低cpu密集型程序的优先级。
实际上,多数程序是混合型。
5. 抢占式调度
当一个进程的时间片用完,内核会暂停其运行,并允许新的进程。
若系统没有可运行的进程,则内核会给 一组已经用完时间片的进程,重新补足时间片,并再次让他们运行。
如此,所有进程都能得以运行。
若系统没有可运行的进程,内核会运行空间进程,空闲进程实际上不是进程,也不会允许(以便节省电池电力)。
空闲进程是内核的特殊例程,用于简化调度程序算法。
若有一个进程正在运行,突然一个高优先级进程变成可运行的(可能因为键盘输入),于是进程会立即暂停当前正在
运行的进程,并运行优先级高的进程。
因此,当前有时间片的优先级最高的进程绝不可能 进程可运行态,但是未运行状态。
正在运行的进程往往是系统中优先级最高的可运行进程。
5.1 完全公平调度
上面的调度方法的过时的,
完全公平调度 更优调度算法,特点是没有时间片,而用时间比例。
比如,CFS给N个进程分别分配1/N的处理器时间,然后CFS通过优先级计算每个进程的比列以调整分配,
默认优先级为0,权值为1,则比列不变,优先级的值越小,权值越高,增加分配比列。
为了避免比例太小导致只够进程切换消耗,所以 引入 最小粒度,最小粒度为 时间长度的基本单位。
6. 线程
每个线程有自己的虚拟处理器:一套寄存器,指令指针,处理状态。
对linux内核而言,线程是独特的进程,内核将两个线程所组成的进程,看作 两个共享内核资源(地址空间,所打开的文件等)的进程。
7. 让出处理器
int sched_yield(void);
linux虽然是抢占式,但也提供了一个系统调用,让进程可以主动放出执行权。
若存在其他可运行进程,sched_yield 的调用进程会暂停,内核会将其放到可运行进程列表尾部,并选出一个新的进程运行。
若不存在任何其他进程,sched_yield 的调用进程不会暂停,而继续执行。
7.1 sched_yield的用途
首先进程调度应该交给内核,因为内核能看到所有的进程,以安排最优调度策略。
sched_yield的可能用途
- 等待外部事件。
以生产消费者为例
do { while (producer_not_ready()) sched_yield(); process_data(); } while (!time_to_quit());
但是,unix上不会这样写,因为又更好的方法:事件驱动。
如上面用一个管道代替 sched_yield。
总之,unix程序应该把目标放在依赖可阻塞的fd的事件驱动解决方案上。
- 线程锁定
一个线程需要获得另一个线程持有的锁,则应该让出cpu,让另一个线程释放锁。这个方法很简单,有效。
可替代方法: 现代linux线程实现(new posix threading library NPTL)有一个使用
futexes(为用户空间锁提供内核的支持)的优化解决方案。
8. 进程优先级
linux根据进程优先级对进程进行调度,
优先级会影响进程何时运行,和运行多久。
nice值为 [-20, 19] 默认为0。
8.1 设置优先级
int getpriority(int which, int who); int setpriority(int which, int who, int prio);
返回当前进程优先级
ret = getpriority(PRIO_PROCESS, 0);
设置当前进程组所有进程优先级为10
ret = setpriority(PRIO_PGRP, 10);
8.2 IO优先级
IO优先级 影响 进程IO请求,IO调度程序会先服务IO优先级高的进程的请求。
默认情况下,IO调度程序使用进程nice值确定IO优先级。因此设置nice值自动变更IO优先级。
9. 处理器亲和性
由于多核环境下,若进程移动cpu,有如下弊端:
- 原cache数据作废
- 不能访问原cache中的数据
所以进程调度程序会尽可能让一个进程安排特定cpu来运行。
但又由于cpu负载可能不均衡,所以当负载不均衡时,调度程序会让进程移动到较空闲的cpu。
有时进程需要一定一直绑定在特定处理器,linux提供了相关系统调用。
放心不会导致cpu负载不均衡,因为调度程序会移动其他进程。
获得进程pid的cpu亲和性,当Pid为0,表示获得当前进程。
cpu_set_t set; int i; CPU_ZERO(&set); sched_getaffinity(0, sizeof(cpu_set_t), &set); for (i = 0; i < CPU_SETSIZE; i++) { int cpu; cpu = CPU_ISSET (i, &set); printf("cpu = %i is %s\n", i, cpu ? "set" : "unset"); }
若打印
cpu=0 is set cpu=1 is set cpu=2 is unset
若希望只运行在cpu0上,可以这么做
cpu_set_t set; int i; CPU_ZERO(&set); CPU_SET(0, &set); CPU_CLR(1, &set); // 这是多余的,因为上面已经清零,但为了完成性 sched_setaffinity(0, sizeof(cpu_set_t), &set); for (i = 0; i < CPU_SETSIZE; i++) { int cpu; cpu = CPU_ISSET (i, &set); printf("cpu = %i is %s\n", i, cpu ? "set" : "unset"); }
成功后,打印
cpu=0 is set cpu=1 is unset cpu=2 is unset
这篇关于linux系统编程——进程管理——高级的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-18git仓库有更新,jenkins 自动触发拉代码怎么配置的?-icode9专业技术文章分享
- 2024-12-18Jenkins webhook 方式怎么配置指定的分支?-icode9专业技术文章分享
- 2024-12-13Linux C++项目实战入门教程
- 2024-12-13Linux C++编程项目实战入门教程
- 2024-12-11Linux部署Scrapy教程:新手入门指南
- 2024-12-11怎么将在本地创建的 Maven 仓库迁移到 Linux 服务器上?-icode9专业技术文章分享
- 2024-12-10Linux常用命令
- 2024-12-06谁看谁服! Linux 创始人对于进程和线程的理解是…
- 2024-12-04操作系统教程:新手入门及初级技巧详解
- 2024-12-04操作系统入门:新手必学指南