嵌入式linux-进程状态与进程关系

news2024/11/28 6:26:08

1. 进程状态

1.1什么是进程状态

Linux 系统下进程通常存在 6 种不同的状态,分为:就绪态、运行态、僵尸态、可中断睡眠状态(浅度
睡眠)、不可中断睡眠状态(深度睡眠)以及暂停态。
下面我们来一一总结一下:

进程状态含义
就绪态(Ready)指该进程满足被 CPU 调度的所有条件但此时并没有被调度执行,只要得到 CPU就能够直接运行;意味着该进程已经准备好被 CPU 执行,当一个进程的时间片到达,操作系统调度程序会从就绪态链表中调度一个进程;
运行态指该进程当前正在被 CPU 调度运行,处于就绪态的进程得到 CPU 调度就会进入运行态;
僵尸态僵尸态进程其实指的就是僵尸进程,指该进程已经结束、但其父进程还未给它“收尸”
可中断睡眠状态可中断睡眠也称为浅度睡眠,表示睡的不够“死”,还可以被唤醒,一般来说可以通过信号来唤醒;
不可中断睡眠状态不可中断睡眠称为深度睡眠,深度睡眠无法被信号唤醒,只能等待相应的条件成立才能结束睡眠状态。把浅度睡眠和深度睡眠统称为等待态(或者叫阻塞态),表示进程处于一种等待状态,等待某种条件成立之后便会进入到就绪态;所以,处于等待态的进程是无法参与进程系统调度的。
暂停态暂停并不是进程的终止,表示进程暂停运行,一般可通过信号将进程暂停,譬如 SIGSTOP信号;处于暂停态的进程是可以恢复进入到就绪态的,譬如收到 SIGCONT 信号

一个新创建的进程会处于就绪态,只要得到 CPU 就能被执行。以下列出了进程各个状态之间的转换关系,如下所示:
在这里插入图片描述

1.2 进程关系

进程号(进程 ID、PID),也有自己的生命周期,进程都有自己的父进程、而父进程也有父进程,这就形成了一个以 init 进程为根的进程家族树;当子进程终止时,父进程会得到通知并能取得子进程的退出状态。

除此之外,进程间还存在着其它一些层次关系,譬如进程组和会话;所以,由此可知,进程间存在着多种不同的关系,主要包括:无关系(相互独立)、父子进程关系、进程组以及会话。

  1. 无关系
    两个进程间没有任何关系,相互独立。

  2. 父子进程关系
    两个进程间构成父子进程关系,譬如一个进程 fork()创建出了另一个进程,那么这两个进程间就构成了父子进程关系,调用 fork()的进程称为父进程、而被 fork()创建出来的进程称为子进程;当然,如果“生父”先与子进程结束,那么 init 进程(“养父”)就会成为子进程的父进程,它们之间同样也是父子进程关系。

  3. 进程组
    每个进程除了有一个进程 ID、父进程 ID 之外,还有一个进程组 ID,用于标识该进程属于哪一个进程组,进程组是一个或多个进程的集合,这些进程并不是孤立的,它们彼此之间或者存在父子、兄弟关系,或者在功能上有联系。

tips:Linux 系统设计进程组实质上是为了方便对进程进行管理。假设为了完成一个任务,需要并发运行 100个进程,但当处于某种场景时需要终止这 100 个进程,若没有进程组就需要一个一个去终止,这样非常麻烦且容易出现一些问题;有了进程组的概念之后,就可以将这 100 个进程设置为一个进程组,这些进程共享一个进程组 ID,这样一来,终止这 100 个进程只需要终止该进程组即可。

注意:关于进程组需要注意以下以下内容:

  1. 每个进程必定属于某一个进程组、且只能属于一个进程组;
  2. 每一个进程组有一个组长进程,组长进程的 ID 就等于进程组 ID;
  3. 在组长进程的 ID 前面加上一个负号即是操作进程组;
  4. 组长进程不能再创建新的进程组;
  5. 只要进程组中还存在一个进程,则该进程组就存在,这与其组长进程是否终止无关;
  6. 一个进程组可以包含一个或多个进程,进程组的生命周期从被创建开始,到其内所有进程终止或离开该进程组;
  7. 默认情况下,新创建的进程会继承父进程的进程组 ID。

1.2.1 getpgid()函数与getpgrp()函数的使用

#include <unistd.h>

pid_t getpgid(pid_t pid);
pid_t getpgrp(void);

下面是进程代码编写:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
 pid_t pid = getpid();
 printf("进程组 ID<%d>---getpgrp()\n", getpgrp());
 printf("进程组 ID<%d>---getpgid(0)\n", getpgid(0));
 printf("进程组 ID<%d>---getpgid(%d)\n", getpgid(pid), pid);
 exit(0);
}

在这里插入图片描述
从上面的结果可以发现,其新创建的进程对应的进程组 ID 等于该进程的 ID。

1.2.2 setpgid()函数 或 setpgrp()函数的使用

调用系统调用 setpgid()或 setpgrp()可以加入一个现有的进程组或创建一个新的进程组,其函数原型如下所示:

#include <unistd.h>

int setpgid(pid_t pid, pid_t pgid);
int setpgrp(void);

setpgid()函数将参数 pid 指定的进程的进程组 ID 设置为参数 gpid。如果这两个参数相等(pid==gpid),则由 pid 指定的进程变成为进程组的组长进程,创建了一个新的进程;如果参数 pid 等于 0,则使用调用者的进程 ID;另外,如果参数 gpid 等于 0,则创建一个新的进程组,由参数 pid 指定的进程作为进程组组长进程。setpgrp()函数等价于 setpgid(0, 0)。

此外,一个进程只能为它自己或它的子进程设置进程组 ID,在它的子进程调用 exec 函数后,它就不能更改该
子进程的进程组 ID 了。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
 printf("更改前进程组 ID<%d>\n", getpgrp());
 setpgrp();
 printf("更改后进程组 ID<%d>\n", getpgrp());
 exit(0);
}

这个结果就不运行了!

1.3 会话

介绍完进程组之后,再来看下会话,会话是一个或多个进程组的集合,其与进程组、进程之间的关系如下图所示:
在这里插入图片描述
一个会话可包含一个或多个进程组,但只能有一个前台进程组,其它的是后台进程组;每个会话都有一个会话首领(leader),即创建会话的进程。一个会话可以有控制终端、也可没有控制终端,在有控制终端的情况下也只能连接一个控制终端,这通常是登录到其上的终端设备(在终端登录情况下)或伪终端设备(譬如通过 SSH 协议网络登录),一个会话中的进程组可被分为一个前台进程组以及一个或多个后台进程组。

会话的首领进程连接一个终端之后,该终端就成为会话的控制终端,与控制终端建立连接的会话首领进程被称为控制进程;产生在终端上的输入和信号将发送给会话的前台进程组中的所有进程,譬如 Ctrl + C(产生 SIGINT 信号)、Ctrl + Z(产生 SIGTSTP 信号)、Ctrl + \(产生 SIGQUIT 信号)等等这些由控制终端产生的信号。

当用户在某个终端登录时,一个新的会话就开始了;当我们在 Linux 系统下打开了多个终端窗口时,实际上就是创建了多个终端会话。

一个进程组由组长进程的 ID 标识,而对于会话来说,会话的首领进程的进程组 ID 将作为该会话的标识,也就是会话 ID(sid),在默认情况下,新创建的进程会继承父进程的会话 ID。通过系统调用 getsid()可以获取进程的会话 ID,其函数原型如下所示:

#include <unistd.h>

pid_t getsid(pid_t pid);

写个最简单的查看会话代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
 printf("会话 ID<%d>\n", getsid(0));
 exit(0);
}

在这里插入图片描述
同理可得:
使用setsid()可以创建一个会话,如下方所示:

#include <unistd.h>

pid_t setsid(void);

如果调用者进程不是进程组的组长进程,调用 setsid()将创建一个新的会话,调用者进程是新会话的首领进程,同样也是一个新的进程组的组长进程,调用 setsid()创建的会话将没有控制终端。setsid()调用成功将返回新会话的会话 ID;失败将返回-1,并设置 errno。

本文参考正点原子的嵌入式LinuxC应用编程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/166652.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据湖之Hudi基础:入门介绍和编译部署

主要记录下Hudi的概述和打包编译等内容&#xff0c;方便参考 文章目录简介官网发展历史Hudi特性使用场景安装部署编译环境准备编译hudi1.源码包上传到服务器2.修改pom文件3.修改源码兼容hadoop34.手动安装kafka依赖&#xff08;非必须&#xff09;5.解决spark模块依赖冲突6.执行…

【基础篇】4 # 链表(上):如何实现LRU缓存淘汰算法?

说明 【数据结构与算法之美】专栏学习笔记 链表结构 数组需要一块连续的内存空间来存储&#xff0c;对内存的要求比较高&#xff0c; 而链表并不需要一块连续的内存空间&#xff0c;它通过指针将一组零散的内存块串联起来使用。 结点&#xff1a;指的是内存块后继指针 next…

Postgresql源码(98)lex与yacc的定制交互方式

1 背景知识一&#xff1a;LEX %option prefix Postgresql中使用%option prefix"core_yy"&#xff0c;影响范围&#xff1a;yy_create_buffer,yy_delete_buffer,yy_flex_debug,yy_init_buffer,yy_flush_buffer,yy_load_buffer_state,yy_switch_to_buffer,yyin,yyleng…

【并发编程十一】c++线程同步——future

【并发编程十一】c线程同步——future一、互斥二、条件变量三、future1、promise1.1、子线程设值&#xff0c;主线程获取1.2、主线程设置值&#xff0c;子线程获取1.3、shared_future2、async2.1、不开新线程的async2.2、开新线程的async3、packaged_task3.1、不使用bind3.2、提…

Kafka-概述

一、Kafka是什么 1.定义 Apache Kafka 是一款开源的消息引擎系统。 消息引擎系统是一组规范。企业利用这组规范在不同系统之间传递语义准确的消息&#xff0c;实现松耦合的异步式数据传递。 二、消息队列的使用场景 传统消息队列的应用场景包括 缓存/削峰、解耦、异步通信 …

vue(透传属性,$attrs)

官方文档 https://cn.vuejs.org/guide/components/attrs.html 案例 <FirstLevel class"attr-test-class" name"zs" age"18"></FirstLevel>FirstLevel组件没有用props去申明name和age&#xff0c;所以这两个属性会透视传递。 <…

RT-Thread系列--组件初始化

一、目的RT-Thread里面有个特别有意思的软件设计叫做组件自动初始化。有些小伙伴可能是第一次听说&#xff0c;所以这边我解释一下&#xff0c;请看下面的代码片段static void clock_init() {// 时钟初始化 } static void uart_init() {// 串口初始化 } static void i2c_init()…

SpringBoot自定义拦截器

&#x1f341;博客主页&#xff1a;&#x1f449;不会压弯的小飞侠 ✨欢迎关注&#xff1a;&#x1f449;点赞&#x1f44d;收藏⭐留言✒ ✨系列专栏&#xff1a;&#x1f449;SpringBoot专栏 &#x1f525;欢迎大佬指正&#xff0c;一起学习&#xff01;一起加油&#xff01; …

JavaScript 浏览器的重排和重绘

文章目录JavaScript 浏览器的重排和重绘概述浏览器解析过程重排重绘优化将多次改变样式的属性操作合并为一次需要多次重排的元素设置为绝对定位减少DOM操作复杂元素处理先设置display为none处理完后再显示缓存频繁操作的属性减少使用table布局使用事件委托绑定事件处理程序利用…

上海亚商投顾:沪指重返3200点 牛市旗手回归!

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪三大指数今日继续走强&#xff0c;沪指重返3200点上方&#xff0c;创业板指午后一度涨近3%&#xff0c;随后涨幅有所…

2023.1. Stimulsoft 报告和仪表板的新版本:Crack

2023.1. Stimulsoft 报告和仪表板的新版本。 发布时间&#xff1a;2022 年 12 月 9 日 我们很高兴地宣布发布 Stimulsoft Reports and Dashboards 2023.1 版&#xff01;我们为 .NET Core 组件添加了对Razor Pages的支持&#xff0c;为PHP和Blazor平台更新了组件。此外&#x…

【Linux】基础:进程间通信

【Linux】基础&#xff1a;进程间通信 摘要&#xff1a;本文主要介绍进程间通信的基础知识&#xff0c;首先将会对进程间通信进行简单概述&#xff0c;其中包括本质目的和方法分类。再介绍对于方法的实现过程&#xff0c;其中有三大类方法&#xff08;管道、System V、POSIX&am…

Kotlin 中变量,类型,表达式,函数详解

博主前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住也分享一下给大家 &#x1f449;点击跳转到教程 一、变量&#xff0c;编译时变量 1、要声明可修改变量&#xff0c;使用var关键字。 2、要声明只读变量&#xff0c;使用…

35岁高龄程序员的 4 条出路,提早布局,避免出局!

目录 一、40岁回首往事&#xff1a;自己竟没有任何核心优势二、公司遇到危机时40岁大龄程序员会怎么样三、适合大龄程序员的几条职业发展路线四、最后的寄语 这篇文章&#xff0c;给大家聊聊Java工程师的职业发展规划的一些思考&#xff0c;同时也给不少20多岁、30多岁&#…

Spark 运行架构

文章目录Spark 运行架构一、运行架构二、核心组件1、Driver2、Executor3、Master & Worker4、ApplicationMaster三、核心概念1、Exuecutor 和 Core2、并行度&#xff08;Parallelism&#xff09;3、有向无环图&#xff08;DAG&#xff09;4、提交流程Yarn Client 模式Spark…

Spring Cloud Gateway(黑马springcloud笔记)

Gateway 目录Gateway一、为什么需要网关二、gateway入门三、断言工厂四、过滤器工厂五、全局过滤1. 实现2. 过滤器执行顺序六、跨域问题一、为什么需要网关 不能让外部能够直接访问微服务&#xff0c;而是需要通过网关访问&#xff1a; 网关的作用&#xff1a; 身份认证和权限…

数据结构与算法基础(王卓)(8):线性表的应用(并集和有序表合并)

PPT&#xff1a;第二章P173&#xff1b; 并集集合&#xff1a;线性表的合并&#xff08;无需有序&#xff0c;不能重复&#xff09; 线性表&#xff1a; Status Union(Sqlist& A, Sqlist& B)//并集 {int len_A A.length;int len_B B.length;for (int i 1; i < …

研究生如何能(较快)找出某领域(去噪)已有算法的创新点或者引入其他领域的新算法?

广义上说&#xff0c;滤波就是给不同的信号分量分配不同的权重&#xff0c;较为复杂的维纳滤波, 是根据信号的统计量设计权重。狭义上说&#xff0c;降噪/去噪&#xff0c;可以看成滤波的一种。降噪的目的在于突出信号本身而抑制噪声影响。从这个角度&#xff0c;降噪就是给信号…

C/C++ 调用规则

平栈&#xff1a;清理参数对调用栈的操作步骤&#xff1a;参数传递三种调用约定&#xff1a;cdecl &#xff08;C调用约定&#xff09;:从右往左传参&#xff0c;参数通过栈传递&#xff0c;调用方(caller)负责平参&#xff08;支持类似printf的不定参&#xff09;stdcall (标准…

hadoop简介

文章目录1&#xff1a;hadoop简介2&#xff1a;Hadoop系统2.1&#xff1a;hadoop架构1&#xff1a;MapReduce2&#xff1a;YARN架构3&#xff1a;HDFS2.2&#xff1a;HDFS、YARN、MapReduce三者关系1&#xff1a;hadoop简介 Hadoop是一个由Apache基金会所开发的分布式系统基础…