在讲进程之前先说一下进程的堆栈的吧:

1.进程的堆栈

内核在创建进程的时候,在创建task_struct的同一时候,会为进程创建对应的堆栈。每一个进程会有两个栈,一个用户栈。存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间执行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。

2.进程用户栈和内核栈的切换

当进程由于中断或者系统调用而陷入内核态之行时。进程所使用的堆栈也要从用户栈转到内核栈。

进程陷入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完毕了用户栈向内核栈的转换;当进程从内 核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器就可以。

这样就实现了内核栈和用户栈的互转。

那么,我们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的。可是在陷入内核的时候,我们是怎样知道内核栈的地址的呢?

关键在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是由于。当进程在用户态执行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态执行的相关信息。可是一旦进程返回到用户态后,内核栈中保存的信息无效,会所有恢复。因此每次进程从用户态陷入内核的时候得到的内核 栈都是空的。所以在进程陷入内核的时候。直接把内核栈的栈顶(从下往上增长的栈)地址给堆栈指针寄存器就能够了。

再来理解一下线程进程的概念:

线程:是进程中的活动对象。每一个线程都用有意个独立的程序计数器,进程栈和一组进程寄存器,内核调度的是线程,而不是进程。

进程:进程就是处于运行期的程序,可是进程并不只局限于一段可运行的程序代码,通常进程还包括其它资源,像打开的文件,挂起的信号。内核内部的数据结构,处理器状态,一个或者多个具有内存映射的内存地址空间及一个或者多个线程,也就是说进程是处于运行期的程序以及相关资源的总称。

进程提供两种虚拟机制:虚拟内存和虚拟处理器;提供给每一个进程一个独立的虚拟处理器以及独立的地址空间,给进程一种独享处理器和拥有整个系统的内存资源的假象。

内核把进程描写叙述符结构(task_struct)存放在一个双向循环链表的任务队列中;

Linux通过slab分配起分配task_struct结构。用slab分配生成的task_struct仅仅须要在栈顶(向上增长的栈)或者栈底(向下增长的栈)创建一个新的结构struct thread_info

进程描写叙述符的存放

内核通过唯一的进程标识值或者PID来标识每个进程,部分硬件体系架构能够用一个专门的寄存器来存放当前进程的task_stuct指针。用于加快訪问速度,x86架构寄存器并不多,所以智能在内核栈尾端创建thread_info结构,通过计算偏移间接地查找task_struct结构。

进程状态:

TASK_RUNNING:运行。进程是可运行的,或者是它正在运行;

TASK_INTERRUPTIBLE:可中断。进程正在睡眠或者堵塞,等待某些条件的达成。

TASK_UNINTERRUPTIBLE:不可中断,就算是接受到信号也不会被唤醒或者执行,不正确信号做不论什么响应。用的较少;

TASK_TRACED:被其它进程跟踪的进程;

TASK_STOPPED:停止,进程没有投入执行或者不能投入执行;

设置当前进程的状态可用函数:set_task_state(task,state)。

进程的创建

一般的操作系统的产生(spawn)进程的机制:新的地址空间里创建进程,读入可运行文件,最后開始运行。

Linux採用UNIX的实现方式将上述步骤分解到两个单独的函数中去运行:fork()和exit(),fork函数通过拷贝当前进程创建一个子进程,exec函数负责读取可运行文件将其加载地址空间開始运行;

写时拷贝技术:

传统的fork系统调用直接把全部资源复制给子进程。可是可能新创建的子进程运行的程序文件映像并不须要那么多资源那么拷贝就就显得非常浪费了,写时拷贝是一种推迟甚至免除拷贝的技术,仅仅有在须要写入是数据才会被拷贝,内核并不复制整个进程的地址空间。而是父子进程共享一个拷贝。

在数据须要被写入时才会复制;

下图是明显的比較:

普通操作系统创建子进程直接全拷贝数据段。堆。栈:

写时复制技术:内核仅仅为新生成的子进程创建虚拟空间结构,它们来复制于父进程的虚拟到底结构。可是不为这些段分配物理内存,它们共享父进程的物理空间,当父子进程中有更改对应段的行为发生时。再为子进程对应的段分配物理空间。

vfork():这个做法更加火爆,内核连子进程的虚拟地址空间结构也不创建了。直接共享了父进程的虚拟空间。当然了。这样的做法就顺水推舟的共享了父进程的物理空间

fork(),vfork(),_clone()--------> clone()系统调用-------------->do_fork()在kernel/fork.c中,完毕大部分的创建工作----------------->copy_process()让进程開始执行;

Copy_process():完毕创建task_struct内核栈,thread_info结构,task_struct结构,分配PID,拷贝父进程必要的资源,

线程在linux中的实现:

从内核的角度来看,是没有线程的概念的,linux把全部的线程当进程来实现的,内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。线程只被视为一个与进程共享某些资源的进程。每一个线程都有自己的task_struct,

线程的创建:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND , 0 );

上面的代码产生的结果和fork差点儿相同,仅仅是父子俩共享地址空间,文件系统资源,文件描写叙述符和信号处理程序。一个普通的fork例如以下:

clone( SIGHLD , 0);

Vfork的实现:

Clone(CLONE_VFORK | CLONE_VM | SIGHLD,0);

内核线程并没有独立的地址空间。它们仅仅有在内核空间中执行,从不切换到用户空间去;新任务使用kthread内核进程通过clone系统调用创建的,新创建的内核线程处于不可执行状态;假设不通过wake_up_process唤醒他不主动执行;只是创建一个内核线程并让它执行起来能够通过kthread_run来达到;相当于kthread_create()和wake_up_process()执行;

进程终结:进程析构它发生在进程调用exit系统调用时,do_exit()完毕大部分工作:删除内核定时器。释放mm_struct,离开队列,引用计数降低(为0释放)。为子进程找养父,处于僵死状态,删除进程(任务队列)。释放僵死进程资源,通知其父进程,释放task_struct内核栈,thread_info占的页。并释放task_struct所占的告诉缓存的slab;


<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

阅读(61) | 评论(0) | 转发(0) |

linux内核——进程管理的更多相关文章

  1. Linux内核——进程管理与调度

    进程的管理与调度 进程管理 进程描写叙述符及任务结构 进程存放在叫做任务队列(tasklist)的双向循环链表中.链表中的每一项包括一个详细进程的全部信息,类型为task_struct,称为进程描写叙 ...

  2. Linux内核 ——进程管理之进程诞生(基于版本4.x)

    <奔跑吧linux内核>3.1笔记,不足之处还望大家批评指正 进程是Linux内核最基本的抽象之一,它是处于执行期的程序.它不仅局限于一段可执行代码(代码段),还包括进程需要的其他资源.在 ...

  3. Linux内核——进程管理之CFS调度器(基于版本4.x)

    <奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...

  4. Linux内核——进程管理之SMP负载均衡(基于版本4.x)

    <奔跑吧linux内核>3.3笔记,不足之处还望大家批评指正 根据实际物理属性,CPU域分类如图1所示. 图1 CPU域分类 问题一:一个4核处理器中的每个物理CPU拥有独立L1 cach ...

  5. linux内核 进程管理

    进程和线程 进程不单单包含可执行代码(代码段),好包含打开的文件,挂起的信号,处理器状态,虚拟内存地址等. 线程:从内核的角度来说,它并没有线程这个概念.Linux把所有线程都当做进程来实现.内核并没 ...

  6. Linux内核电源管理综述

    资料:http://blog.csdn.net/bingqingsuimeng/article/category/1228414http://os.chinaunix.net/a2006/0519/1 ...

  7. Linux操作系统的进程管理

    Linux操作系统的进程管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程相关概念 1>.进程概述 内核的功用: 进程管理.文件系统.网络功能.内存管理.驱动程序. ...

  8. linux 系统管理--进程管理

    目录 linux 系统管理--进程管理 一.进程基本概述 二.监控进程状态 三.进程的优先级[进阶] 四.企业案例,Linux假死是怎么回事 五.后台进程管理 六.系统平均负载[进阶] linux 系 ...

  9. .Neter玩转Linux系列之五:crontab使用详解和Linux的进程管理以及网络状态监控

    一.crontab使用详解 概述:任务调度:是指系统在某个时间执行的特定的命令或程序. 任务调度分类: (1)系统工作:有些重要的工作必须周而 复始地执行. (2)个别用户工作:个别用户可能希望执 行 ...

随机推荐

  1. python 爬虫 处理超级课程表传输的数据

    借鉴的别人的思路 http://www.oschina.net/code/snippet_2463131_53711 抓取超级课程表传输的数据 他的传输数据居然是明文的-- 现在已经把自己的课表都抓出 ...

  2. POJ Anniversary party 树形DP

    /* 树形dp: 给一颗树,要求一组节点,节点之间没有父子关系,并且使得所有的节点的权值和最大 对于每一个节点,我们有两种状态 dp[i][0]表示不选择节点i,以节点i为根的子树所能形成的节点集所能 ...

  3. Python如何import文件夹下的文件

    Python的import包含文件功能就跟PHP的include类似,但更确切的说应该更像是PHP中的require,因为Python里的import只要目标不存在就报错程序无法往下执行.要包含目录里 ...

  4. C++ Primer 学习笔记_34_STL实践与分析(8) --引言、pair类型、关联容器

    STL实践与分析 --引言.pair类型.关联容器 引言:     关联容器与顺序容器的本质差别在于:关联容器通过键[key]来存储和读取元素,而顺序容器则通过元素在容器中的位置顺序的存取元素. ma ...

  5. Oracle中空值与数字相加问题

    select 10 + 10 + 10 from dual 结果是30,全然没问题. select null + 10 + 10 from dual 结果是空串,但期望的结果是20. select n ...

  6. C#程序集系列04,在程序集包含多个module的场景下理解关键字internal

    本篇在一个程序集包含多个module的场景下体验internal的含义. →查看F盘as文件夹下的文件→删除MainClass.exe→把MyFirstModule和MySecondModule组装到 ...

  7. 23LINQ运算符返回其它类型实例汇总

      IEnumerable<T>返回其它集合类型 ToArray() ToList() ToDictionary() ToLookUp()     返回集合中的元素 □ ElementAt ...

  8. merge into优化sql(转)

    使用Merge INTO优化SQL,性能提升巨大 分类: Oracle 2017-04-13 10:55:07   说说背景:开发有个需求,需要对新加的一个字段根据特定的业务逻辑更新数据.TPS_TR ...

  9. Android的基本常用的短信操作

    1.调用系统发送短信界面(传入手机号码+短信内容) 2.隐藏发送短信(指定号码指定内容)(这里隐藏只是没有反写入数据库) 3.获得收件箱接收到的短信 4.Android屏蔽新短信通知提示信息:(Con ...

  10. 在Windows Phone项目中调用C语言DLL

    在Windows Phone项目中调用C语言写的DLL 最近接到一个需求,需要在WP里调用一个C语言写的DLL,并且说Android和iOS都可以,问我WP是否可以这样? 我说我调研一下,就有了下面的 ...