一、进程与线程

进程是处于执行期的程序,但是并不仅仅局限于一段可执行程序代码。通常,进程还要包含其他资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程,当然还包括用来存放全局变量的数据段等。在Linux内核中,进程也通常叫做任务

执行线程,简称线程,是在进程中活动的对象。每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。内核调度的对象是线程,而不是进程。在传统的UNIX系统中,一个进程只包含一个线程,但在现在的系统中,包含多个线程的多线程程序司空见惯。在Linux系统中,线程和进程并不特别区分,对Linux而言,线程是一种特殊的进程

Linux实现线程的机制很独特。从内核角度来说,它并没有线程这个概念。Linux把所有的线程都当做进程来实现。内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯一隶属于自己的 task_struct ,所以在内核中,它看起来就像是一个普通的进程。

二、进程描述符及任务结构

1)进程描述符

内核把进程的列表存放在任务队列中,任务队列是一个双向循环链表如图1所示。链表中每一项都是类型为 task_struct 的结构体,被称为 进程描述符,该结构定义在 <linux/sched.h>文件中。进程描述符中包含一个具体进程的所有信息。进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件、进程的地址空间、挂起的信号、进程的状态以及其他信息。

图1 进程描述符及任务队列

Linux通过slab分配器分配 task_struct 结构,这样能达到对象复用和缓存着色的目的,为了找到 task_struct,只需在栈底(对于向下增长的栈)或栈顶(对于向上增长的栈)创建一个新的结构 struct thread_info,该结构存放着指向任务实际 task_struct 的指针。结构的定义如下:

struct thread_info{
struct task_struct *task;
struct exec_domain *exec_domain;
_u32 flags;
_u32 status;
_u32 cpu;
int preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
void *sysenter_return;
int uaccess_err;
};

2)进程状态

进程描述符中的 state 域描述了进程的当前状态。系统中进程的状态大致有以下这几种:

TASK_RUNNING(运行) 表示进程正在执行,或者在运行队列中等待执行;
TASK_INTERRUPTIBLE(可中断)

表示进程正在睡眠(被阻塞),等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置为运行,处于此状态的进程也会因为接收到信号而提前被唤醒并随时准备投入运行;

 TASK_UNINTERRUPTIBLE(不可中断) 除了就算接收到信号也不会被唤醒或者准备投入运行外,这个状态与可中断状态相同。这个状态通常在进程必须等待时不受干扰或者等待事件很快就会发生时出现;
__TASK_TRACED 被其他进程跟踪的进程;
 __TASK_STOPPED(停止)

进程停止执行,进程没有投入运行也不能投入运行。通常,这种状态发生在接收到 SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态。

EXIT_ZOMBIE(僵死状态)

进程已经退出,但是进程本身所占的内存还没有被释放,如进程描述符等结构还保留着,以便父进程能够获得其停止运行的信息。当父进程获得需要的信息或者通知内核剩余的信息没用时,进程所占有的剩余的资源将被释放

EXIT_DEAD(死亡状态) 进程所占用的所有资源完全被释放

可以使用 set_task_state(task,state) 函数来设置当前进程状态:

set_task_state(task,state);        // 将进程task的状态设置为 state

三、进程创建

linux使用 fork() 和 exec() 函数来创建进程。首先,使用 fork()函数拷贝当前进程创建一个子进程,这个子进程与父进程之间的区别仅在于 PID、PPID 以及某些资源统计量不同;然后调用 exec() 函数,把当前进程映像替换成新的进程文件,得到一个新程序。

传统的 fork() 系统调用直接把所有的资源复制给新创建的进程。这种实现过于简单且效率低下,因为它拷贝的数据也许并不共享。Linux 的 fork() 使用写时拷贝页实现,写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才会进行,在此之前,只是以只读的方式共享。这种技术使得地址空间上的页的拷贝被推迟到实际发生写入的时候才进行。在页根本不会被写入的情况下,它们就无须复制了。

四、进程终结

调用 do_exit() 来终结进程。当一个进程被终结时,内核必须释放它所占有的资源,并告知其父进程。

在调用 do_exit() 之后,尽管线程已经僵死不能再运行了,但是系统还是保留了它的进程描述符。在父进程获得已终结的子进程的信息后,或者通知内核它并不关注那些信息后,子进程的 task_struct 结构才被释放。调用 release_task() 来释放进程描述符。

Linux内核学习笔记(1)-- 进程管理概述的更多相关文章

  1. Linux内核学习笔记-2.进程管理

    原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  2. Linux内核学习笔记二——进程

    Linux内核学习笔记二——进程   一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...

  3. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  4. Linux内核学习笔记-1.简介和入门

    原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  5. linux kernel学习笔记-5内存管理_转

    void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...

  6. 20135316王剑桥Linux内核学习笔记

    王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...

  7. Linux内核学习笔记——内核内存管理方式

    一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...

  8. Linux内核入门到放弃-进程管理和调度-《深入Linux内核架构》笔记

    进程优先级 硬实时进程 软实时进程 普通进程 O(1)调度.完全公平调度器 抢占式多任务处理(preemptive multitasking):各个进程都分配到一定的时间段可以执行.时间段到期后,内核 ...

  9. (笔记)Linux内核学习(二)之进程

    一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器. 内核调度的对象是线程而不是进程.对 ...

随机推荐

  1. Gradle Goodness: Excluding Tasks for Execution

    In Gradle we can create dependencies between tasks. But we can also exclude certain tasks from those ...

  2. 允许跨域资源共享(CORS)携带 Cookie (转载)

    如何让CORS携带Cookie CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing).默认浏览器为了安全,遵循“同源策略”,不允许 Aj ...

  3. ODI使用流程

    ---恢复内容开始--- ODI流程 Topology 1.建立 源 物理结构体系 2.建立 目的 物理结构体系 步骤同上 3.建立 源 逻辑架构 4.建立 目的 逻辑架构 步骤同上 Designer ...

  4. Caused by: java.lang.ClassNotFoundException: org.springframework.boot.bind.RelaxedPropertyResolver

    Caused by: java.lang.ClassNotFoundException: org.springframework.boot.bind.RelaxedPropertyResolver 这 ...

  5. jquery 60s倒计时

    前端开发中经常用到的发送按钮倒计时,每次都是重写,挺麻烦的,记录一下,以后直接来复制代码 <!DOCTYPE html> <html> <head> <met ...

  6. [笔记] 升級到 Delphi 10.2 Tokyo 笔记

    升級到 Delphi 10.2 Tokyo 笔记: 更新 Xcode 8.3 & iOS 10.3 测试: macOS 没问题(可 Debug) iOS Simulator 没问题(可 Deb ...

  7. ElasticSearch 安装root用户启动失败问题解决

    1. 下载ElasticSearch 2.3.3 2.  安装JDK 1.8.0以上版本 3.  ElasticSearch 安装时会出现 Exception in thread "main ...

  8. Python学习手册之Python介绍、基本语法(一)

    一.什么是python? python是一种高级的编程语言.它适合编写一些应用程序,比如:网站编程,脚本编程,科学计算和最近非常热门的AI(人工智能).目前,Google,腾讯,百度,阿里巴巴,豆瓣都 ...

  9. Oracle——系统数据字典常用命令(查看表所属空间层目录等)

    发生背景: 项目前后台交互对接时候,经常存在对底层表蒙圈情况尤其是oracle数据库,所在层级不同会导致操作对象直接的改变,从而发生意向不到的事情:很多时候需要了解我们所操作对象所处的层级等相关信息, ...

  10. MongoDB成为最受开发人员期待的数据库系统

    本文翻译之MongoDB官方博客,原文地址:https://www.mongodb.com/blog/post/stack-overflow-research-developers-mongodb-m ...