7进程控制

12.1进程切换

实际上为用户提供的系统调用服务,用户在执行它的应用的过程当中,有需求要创建一个新的进程,如何来创建一个新的进程,在这里头运行一个新的程序,那这个是进程加载,父进程创建子进程之后,它们俩之间需要有一些协调的关系,比如说子进程结束之后,父进程负责回收它所占用的资源,那这个时候它们之间有一个通讯关系这就是进程的等待和退出

进程切换

进程切换(上下文切换)

暂停当前运行进程,从运行状态变成其他状态

调度另一个进程从就绪状态变成运行状态

进程切换的要求

切换前,保存进程上下文

切换后,恢复进程上下文

快速切换

注:为了保证系统运行的效率,这个切换的速度必须非常快所以通常情况下它都是由汇编来实现的

进程生命周期的信息

寄存器(PC, SP,…)

CPU状态

内存地址空间

精髓:

■进程切换的原因:中断,陷阱(异常)和系统调用


中断:

时钟中断:当前进程时间片用完了

I/O中断:操作系统确定是否发生了I/O活动。

内存失效:要访问的内存不在主存中,要调入内存。

进程控制块PCB:内核的进程状态记录

内核为每个进程维护了对应的进程控制块(PCB)

内核将相同状态的进程的PCB放置在同一队列


精髓:

进程状态的变化

进程切换步骤:

1)保存处理器上下文环境,包括程序计数器和其他寄存器。

2)更新当前处于运行态进程的进程控制块,包括将进程的状态改变到另一状态(就绪态、阻塞态、就绪/挂起态或退出态)。还必须更新其他相关域,包括离开运行态的原因和记账信息。

3)将进程的进程控制块移到相应的队列(就绪、在事件i处阻塞、就绪/挂起)。

4)选择另一个进程执行,这方面的内容将在本书的第四部分探讨。

5)更新所选择进程的进程控制块,包括将进程的状态变为运行态。

6)更新内存管理的数据结构,这取决于如何管理地址转换。

7)恢复处理器在被选择的进程最近一次切换出运行状态时的上下文环境,这可以通过载入程序计数器和其他寄存器以前的值来实现。

12.2进程创建

创建新进程

■Windows进程创建API:CreateProcess(filename)

创建时关闭所有在子进程里的文件描述符CreateProcess(filename, CLOSE_FD)

创建时改变子进程的环境CreateProcess(filename, CLOSE_FD, new_envp)

■Unix进程创建系统调用:fork/exec

·fork()把一个进程复制成二个进程

parent (old PID), child (new PID)

·exec()用新程序来重写当前进程

PID没有改变

■用fork和exec创建进程的示例

int pid = fork();//创建子进程

if(pid == 0) {//子进程在这里继续

// Do anything (unmap memory, close net connections…)

exec(“program”, argc, argv0, argv1,…);

}

■fork()创建一个继承的子进程

复制父进程的所有变量和内存

复制父进程的所有CPU寄存器(有一个寄存器例外)

■fork()的返回值

子进程的fork()返回0

父进程的fork()返回子进程标识符

fork()返回值可方便后续使用,子进程可使用getpid()获取PID

fork()的地址空间复制

■fork()执行过程对于子进程而言,是在调用时间对父进程地址空间的一次复制


对于父进程fork()返回child PID,对于子进程返回值为0

程序加载和执行

系统调用exec( )加载新程序取代当前运行进程

exec()示例代码

main()

int pid = fork();//创建子进程

if (pid == 0) {//子进程在这里继续

exec_status = exec(“calc”, argc, argv0, argv1,…);

printf(“Why would I execute?”);

}  else {//父进程在这里继续

printf(“Whose your daddy?”);

child_status = wait(pid);

}


fork()使用示例(循环内fork()父子都同时产生新的子进程)

int  main()

{

pid_t  pid;

int  i;

for  (i=0;  i

{

/* fork  another  process  */

pid = fork();

if  (pid < 0) { /*error  occurred  */

fprintf(stderr,“Fork Failed”);

exit(-1);

}

else if (pid == 0) { /* child process */

fprintf(stdout,“i=%d,  pid=%d,  parent  pid=%d\n”,I,

getpid() ,getppid());

}

}

wait(NULL);

exit(0);

}


Fork()的开销?

■fork()的实现开销

对子进程分配内存

复制父进程的内存和CPU寄存器到子进程里

开销昂贵!!

■在99%的情况里,我们在调用fork()之后调用exec()

在fork()操作中内存复制是没有作用的

子进程将可能关闭打开的文件和连接

为什么不能结合它们在一个调用中?

■vfork()

创建进程时,不再创建一个同样的内存映像

一些时候称为轻量级fork()

子进程应该几乎立即调用exec()

现在使用Copy on Write  (COW)技术

■父进程终止其子进程的原因有很多

子进程使用了超过它所分配到的一些资源。(为判定是否发生这种情况,要求父进程有一个检查其子进程状态的机制。)

分配给子进程的任务已不再需要

父进程退出,如果父进程终止,那么操作系统不允许子进程继续。

精髓:创建一个新进程,一般步骤:

1)给新进程分配一个唯一的进程标识符。此时,在主进程表中增加一个新表项,表中的每个新表项对应着一个进程。

2)给进程分配空间。这包括进程映像中的所有元素。因此,操作系统必须知道私有用户地址空间(程序和数据)和用户栈需要多少空间。可以根据进程的类型使用默认值,也可以在作业创建时根据用户请求设置。如果一个进程是由另一个进程生成的,则父进程可以把所需的值作为进程创建请求的一部分传递给操作系统。如果任何现有的地址空间被这个新进程共享,则必须建立正确的连接。最后,必须给进程控制块分配空间。

3)初始化进程控制块。进程标识符部分包括进程ID和其他相关的ID,如父进程的ID等;处理器状态信息部分的大多数项目通常初始化成0,除了程序计数器(被置为程序人口点)和系统栈指针(用来定义进程栈边界);进程控制信息部分的初始化基于标准默认值和为该进程所请求的属性。例如,进程状态在典型情况下被初始化成就绪或就绪/挂起;除非显式地请求更高的优先级,否则优先级的默认值为最低优先级;除非显式地请求或从父进程处继承,否则进程最初不拥有任何资源( I/O设备、文件)。

4)设置正确的连接。例如,如果操作系统把每个调度队列都保存成链表,则新进程必须放置在就绪或就绪/挂起链表中。

5)创建或扩充其他数据结构。例如,操作系统可能为每个进程保存着一个记账文件,可用于编制账单和/或进行性能评估。

12.3程序加载和执行系统调用exec()

程序加载和执行系统调用exec()

■允许进程“加载”一个完全不同的程序,并从main开始执行(即_start)

■允许进程加载时指定启动参数(argc, argv)

■exec调用成功时

它是相同的进程…

但是运行了不同的程序

■代码段、堆栈和堆(heap)等完全重写

12.4进程等待与退出

父进程等待子进程

■wait()系统调用用于父进程等待子进程的结束

子进程结束时通过exit()向父进程返回一个值

父进程通过wait()接受并处理返回值

■wait()系统调用的功能

有子进程存活时,父进程进入等待状态,等待子进程的返回结果

当某子进程调用exit()时,唤醒父进程,将exit()返回值作为父进程中wait的返回值

有僵尸子进程等待时,wait()立即返回其中一个值

无子进程存活时,wait()立刻返回

进程的有序终止exit()

■进程结束执行时调用exit(),完成进程资源回收

■exit()系统调用的功能

将调用参数作为进程的“结果”

关闭所有打开的文件等占用资源

释放内存

释放大部分进程相关的内核数据结构

检查是否父进程是存活着的

如存活,保留结果的值直到父进程需要它,进入僵尸(zombie/defunct)状态,等待父进程处理

如果没有,它释放所有的数据结构,进程结果(孤儿进程)

清理所有等待的僵尸进程

■进程终止是最终的垃圾收集(资源回收)

其他进程控制系统调用

■优先级控制

nice()指定进程的初始优先级

Unix系统中进程优先级会随执行时间而衰减

■进程调试支持

ptrace()允许一个进程控制另一个进程的执行

设置断点和查看寄存器等

■定时

sleep()可以让进程在定时器的等待队列中等待指定

进程控制v.s.进程状态

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • Linux 进程管理与程序开发 进程是Linux事务管理的基本单元,所有的进程均拥有自己独立的处理环境和系统资源,...
    JamesPeng阅读 2,450评论 1 14
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,088评论 0 23
  • 2016-02-02 进程控制 进程标识 每个进程都有一个非负整型的唯一的进程id,因为进程id表示服总是唯一的,...
    千里山南阅读 429评论 0 0
  • 心里十分焦虑。 婆婆做的太多了,她似乎投入的像一个妈妈的角色,可我才是宝宝的妈妈。 现在出来找工作心里悲戚戚的,感...
    晰言阅读 205评论 0 0
  • 告别母亲,我乘车回到自己的地盘,结束我的大假。 下午无事,其实事多,只是不想做,最后一天,我再做点自己的事情,于是...
    君子兰a阅读 141评论 0 0