前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >理解进程和线程

理解进程和线程

作者头像
theanarkh
发布2020-03-11 15:08:31
7730
发布2020-03-11 15:08:31
举报
文章被收录于专栏:原创分享

进程和线程是操作系统里很重要的概念,但是所有的东西都会落实到代码。看起来很复杂的进程线程,其实在操作系统的代码里。也只是一些数据结构和算法。只不过他比一般的数据结构和算法可能复杂点。但是学习方法还是一样的,就是深入源码,一探究竟。 进程在操作系统里,是用一个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函数会把栈的位置和代码执行的位置(就是我们传进去的函数)告诉系统。系统会从我们定义的函数开始执行。大概如下。

在这里插入图片描述

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 进程的管理
  • 进程的调度
  • 进程的执行时间
  • 信号
  • 状态
  • 文件系统相关
  • 权限
  • 进程关系信息
  • 执行上下文
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档