专栏首页原创分享理解进程和线程

理解进程和线程

进程和线程是操作系统里很重要的概念,但是所有的东西都会落实到代码。看起来很复杂的进程线程,其实在操作系统的代码里。也只是一些数据结构和算法。只不过他比一般的数据结构和算法可能复杂点。但是学习方法还是一样的,就是深入源码,一探究竟。 进程在操作系统里,是用一个task_struct结构体表示的。因为操作系统是大部分是用c语言实现的,没有对象这个概念。如果我们用高级语言来理解的话,每个进程就是一个对象。每次新建一个进程,就是新建一个对象。task_struct结构体可以说是类的定义。我们看一下一个task_struct的定义。

在这里插入图片描述 我们看到task_struct结构体里其实就是保持了一个进程所需要的一些信息,报包括执行状态,执行上下文tss,打开的文件、根目录、工作目录、收到的信号、信号处理函数、代码段、数据段的位置,进程id,执行时间、退出码等等。我们具体看一下这些数据结构的作用。

进程的管理

操作系统里会维护一个task_struct数组或者链表来记录当前系统中所有的进程。每次新建一个进程的时候,就会往里面追加一个task_struct结构体,每次销毁一个进程的时候,该进程的父进程会删除对应的task_struct。

进程的调度

操作系统的运作,很大程度上是由时钟驱动的,电脑中会有一个硬件间歇性地产生时钟中断。中断间隔是由操作系统初始化该硬件时决定的(定时器也是由该硬件驱动的,我们在应用层使用的定时器功能,归根到底还是使用系统的定时器去实现的)。每次时钟中断的时候如果当前执行的进程时间片已到,则会发生进程调度。另外进程阻塞的时候,也会发生进程调度。被调度到的进程,系统就会把task_struct里的tss信息加载到cpu。包括当前执行的代码位置,各种寄存器的值。然后就完成了进程的切换。

进程的执行时间

每次时钟中断的时候,时钟中断处理程序都会累加当前进程的执行时间,我们平时查看的进程的执行时间,这些数据就是由这些字段记录的。一个进程在内核态和用户态下执行的时间,是分开计算的。

信号

task_struct中用三个字段实现了信号相关的功能,一个是signal,记录了进程收到的信号,按位计算。blocked就是记录当前进程不接收哪些信号。sigaction则是记录每个信号对应的处理函数,和signal一一对应。每次我们调用kill的时候,其实就是修改signal字段的值。然后在某些时机下,系统会执行sigaction里对应的函数。这些时机包括系统调用返回,时钟中断处理程序返回、还有其他的硬件中断返回等等。

状态

task_struct用一个字段state记录了进程当前的状态,exit_code记录进程退出时的退出码。

文件系统相关

当前进程的根目录、工作目录。我们平时在进程里打开一个文件的时候,如果没有写明绝对路径,系统就会以工作目录为基础,加上我们传的相对路径拼出绝对路径。从而找到文件。另外filp字段是维护进程打开的文件信息。我们平时拿到的文件描述符就是filp字段的索引。他会逐步找到底层对应的文件或者socket。executable是保存进程对应的二进制文件所在的文件信息。我们都知道程序加载到内存变成进程。executable保存的就是程序对应的文件的信息。

权限

task_struct里用uid、euid、gid、egid等字段记录进程的权限信息。

进程关系信息

pid字段记录了当前进程的id,father记录了父进程的id。pgrp,session,leader分别是组id,会话id,是不是会话leader。多个进程组成一个组,多个组组成一个会话。如果一个进程是这个组或者会话的leader,则他的id会成为组或者会话的id,比如 组1有进程a的id是1(组leader、会话leader)进程b的id是2。 组2有进程c的id是3(组leader),进程d的id是4。 所有进程在一个会话,则组1的所有进程的组id和会话id都是1。组2所有进程的组id是3,会话id是1。

执行上下文

tss_struct和desc_struct结构体记录了进程执行的上下文,每次进程切换的时候,如果是被调度执行,则上下文加载到cpu和对应的硬件中,如果是被挂起,则cpu和硬件的信息保存到上下文。下次执行的时候恢复。

以上就是一个进程所具有的一些属性。我们发现,进程也没有那么难以理解,好比我们平时定义一个人,他有名字,身高,年龄属性一样。每个对象,他都有属于自己的一些属性。

下面我们再来看一下线程。相比进程,线程对很多同学来说可能更难理解。其实对于操作系统来说,没有单独去实现线程这个概念,操作系统把进程和线程抽象成执行上下文。可以说他们是一个东西。但是他们又有一点点区别。我们以linuxthreads线程库为例。了解一下线程是什么。我们知道fork可以新建一个进程。但是这个进程太重了,尽管有些属性是可以共享的。所以操作系统重新实现了一个系统调用clone。他支持更细粒度的属性共享。所以我们称线程是轻量级的进程。顾名思义,线程也是进程,但是他是轻量级的,因为他很多属性都是共享于父进程(父线程)的。共享的属性可以通过clone函数的参数来控制。当我们新建一个线程的时候,系统里会新建一个进程。clone函数会把栈的位置和代码执行的位置(就是我们传进去的函数)告诉系统。系统会从我们定义的函数开始执行。大概如下。

在这里插入图片描述

本文分享自微信公众号 - 编程杂技(theanarkh),作者:theanarkh

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 通过linux0.11理解僵尸进程

    首先僵尸进程产生的原因是子进程退出了,但是父进程没有回收他的资源(pcb),所以我们从源头开始分析这个过程。那就是子进程退出的时候。进程是通过exit系统调用退...

    theanarkh
  • 进程的执行和挂起

    进程是对逻辑的抽象,我们从操作系统的书籍中对进程有了很多的认识,但是对进程的实现可能不太了解,这篇文章尝试解释一下关于进程实现的大致原理。 进程的实现,...

    theanarkh
  • linux0.11进程睡眠唤醒原理分析

    进程的睡眠是通过调用sleep_on函数,该函数修改了进程的状态并且通过schedule函数切换到其他进程执行,从而实现进程的挂起,TASK_UNINTERRU...

    theanarkh
  • 为什么你的docker容器刚启动就停了

    很多docker初学者,在运行容器的时候,或者是写第一个dockerfile的时候,问题最多的就是容器启动后就停了,怎么看都觉得命令没有问题,容器也没有错误日志...

    李俊鹏
  • 2.1进程与线程

    在多道程序同时运行的背景下,进程之间需要共享系统资源,这样就会导致各程序在执行过程中出现相互制约的关系,程序的执行就会表现出间断性的特性。这些特性都是在程序的执...

    week
  • Python实现守护进程

    專 欄 ❈汤英康,Python程序员,负责设计和开发大数据监控平台的相关产品。 PyCon China2016 深圳 讲师。 博客:http://blog.t...

    Python中文社区
  • 2.5.1 进程与程序的区别和联系

    (1)进程是程序及其数据在计算机上的一次运行活动,是一个动态的概念。进程的运行实体是程序,离开程序的进程没有存在的意义。从静态角度看,进程是由程序,数据和进程控...

    week
  • linux进程管理:进程,程序,线程 & 9个进程管理工具 & 作业控制

    程序 ------》系统调用-------》缓存(内存) -------》cpu处理 执行任务

    用户5807183
  • [linux] C语言Linux系统编程进程基本概念

    1.如果说文件是unix系统最重要的抽象概念,那么进程仅次于文件。进程是执行中的目标代码:活动的、生存的、运行的程序。

    陶士涵
  • 进程的描述和创建

    进程在内核态运行时需要自己的堆栈信息,linux内核为每个进程都提供了一个内核栈。对每个进程,Linux内核都把两个不同的数据结构紧凑的存放在一个单独为进程分配...

    0x222进制

扫码关注云+社区

领取腾讯云代金券