linux-进程(2)

1.通过系统调用获取进程标示符

进程id(PID)

父进程id(PPID)

每一个可执行程序运行起来之后都会成为一个进程,每个进程都有一个自己的id,以及一个父进程id,父进程就是创建自己进程的进程,每个进程都是一个执行起来的程序,所以肯定在这个程序中创建另一个程序,就是自己的子进程。

使用getpid这个函数就可以查看到自己这个进程的id,使用getppid这个函数就可以查看到父进程的id,getpid是一个系统调用函数,需要注意的是一个子进程只有对应的一个父进程,但是一个父进程可以有多个子进程。

进程每一次被启动时对应的pid都不一样,但是父进程的pid永远不会变。

#include<iostream>
#include<unistd.h>
#include<sys/types.h>
using namespace std;int main()
{pid_t id=getpid();while(1){cout<<id<<endl;sleep(1);}return 0;
}

int main()
{pid_t id=getpid();pid_t pid=getppid();cout<<"Im child: "<<id<<endl;cout<<"Im father: "<<pid<<endl;return 0;
}

\


2.通过系统调用创建进程-fork初识

这个是fork函数的介绍,需要包含两个头文件,fork函数的返回值是pid_t,并且fork函数有两个返回值。

我们来做一个小测试,看看返回值到底是怎么回事。

#include <unistd.h>
#include <sys/types.h>
#include <iostream>
using namespace std;int main()
{cout << "before fork:Im a process, pid:" << getpid() << ", ppid:" << getppid()<<endl;fork();cout << "after fork:Im a process, pid:" << getpid() << ", ppid:" << getppid()<<endl;sleep(2);return 0;
}

可以看到fork之后的代码被执行了两次,也就是从一个进程变成了两个进程,第三个是子进程,它的ppid就是父进程的pid。

那么我们怎么知道哪个是子进程,哪个是父进程呢?可以通过fork的返回值来判断,如果fork成功则对子进程返回0,对父进程返回子进程的id。此时就可以使用if来分流,让父子进程做不一样的事情。

我们都知道进程=内核数据结构+可执行代码和数据,那么子进程的代码和数据是什么呢?它是怎么运行起来的,实际上父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)。但是进程是具有独立性的,互相之间是不影响的。


3.阻塞状态

大家还需要知道的是,一个cpu只有一个运行队列,那么有些进程在等待硬件资源的时候,就会被os从运行队列中拿出来放到对应的硬件的队列中,并且改成阻塞状态,因为cpu也属于硬件,硬件就有自己的结构体,里面就有对应的队列。

那么当我们用户从硬件中输入数据的时候,这个进程就会被从硬件的队列中拿出来链入到cpu的运行队列,并且将进程状态改为运行状态。

4.阻塞挂起状态

挂起状态通常伴随着阻塞,这个状态的前提是计算机的资源比较吃紧,这个时候os就会将这个进程的代码和数据写入到外设当中,当资源足够时再拿过来,写入的这个过程就是在腾空间。这个写入的本质就是用时间换空间,宁愿让进程慢点,也不要让os挂掉。


5.进程状态

linux内核源代码是这样描述进程的各种状态的。

/*

* The task state array is a strange "bitmap" of * reasons to sleep. Thus "running" is zero, and * you can test for combinations of others with * simple bit tests.

*/

static const char * const task_state_array[] = { "R (running)", /* 0 */

"S (sleeping)", /* 1 */ "D (disk sleep)", /* 2 */ "T (stopped)", /* 4 */ "t (tracing stop)", /* 8 */

"X (dead)", /* 16 */ "Z (zombie)", /* 32 */ };

R运行状态(running) : 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。

D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

进程大多数情况下是大量的在运行,那么os怎么管理这些进程呢?就需要先描述再组织,描述就是数据结构+可执行代码和数据,那么组织就需要使用队列来对进程进行排队,因为大部分进程并不是一直在运行,有些进程也可能在等待资源,比如等待我们从键盘输入,所以进程有许多种状态。
 

那么进程的状态决定了上面呢?决定了后序的动作,那么动作的先后就需要进行排队,每一个cpu都有一个自己的运行队列,那么只有进程被放入了这个运行队列,就都是运行状态,就算在排队也是运行状态。

5.1睡眠状态

睡眠状态也就是进程在等待事件的完成,那么为什么执行了一下的代码,在查询该进程信息的时候,会是睡眠状态呢?这个进程不是一直在运行吗?当我们去掉sleep的时候,这个进程还是s状态,其实是因为cout这个函数的本质是向显示器进行打印,显示器是在我们面前,可是这个可执行程序是在远端的云服务器上运行的,cpu比外设要快很多,所以注定了cout的大部分时间是在等待着执行。

#include<iostream>
#include<unistd.h>
#include<sys/types.h>
using namespace std;int main()
{while(1){cout<<"Im a process, pid: "<<getpid()<<endl;sleep(1);}return 0;
}

当我们去掉cout,死循环里面什么都不做,就能查到是运行状态。 

 进程的睡眠状态其实就是os的阻塞状态,这里的睡眠有时候也叫做可中断睡眠,因为可以用ctrl+c来终止。  

 5.2停止状态

当我们使用kill -19 这条命令就可以使一个进程停止,也就是进入停止状态。

 如果我们还想让这个进程跑起来,可以使用kill -18这个命令。

5.3僵尸状态

僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程

僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。

所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

我们创建进程就是为了给我们完成某件事,那么这个进程退出时就需要给我们返回结果,一个进程在退出时可以释放掉代码和数据,因为都没有用了,但是需要先保存一下pcb,因为需要被os或者其他进程获取到该进程的退出信息,我们把一个进程已经退出但并没有被获取退出信息的状态称为僵尸状态。

下面这段代码就是前5秒父子进程同时运行。后面5秒父进程单独运行,在第5秒时子进程会被强制退出,那么就进入了僵尸状态Z。 为什么要有Z状态呢?我们创建进程就是为了将这个进程完成某个工作, 

int main()
{pid_t id = fork();if (id == 0){int cnt = 5;while (cnt){cout << "Im child, pid: " << getpid() << ", ppid: " << getppid() << endl;sleep(1);cnt--;}exit(0);}int cnt = 10;while (cnt){cnt--;cout << "Im father, pid: " << getpid() << ", ppid: " << getppid() << endl;sleep(1);}wait(NULL);cout<<"father wait child success....."<<endl;return 0;
}

  僵尸进程危害

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!

维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护?是的!

那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!

内存泄漏?是的!

 5.4孤儿状态

父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?

父进程先退出,子进程就称之为“孤儿进程”

孤儿进程被1号init进程领养,当然要有init进程回收喽。

当父进程退出之后,子进程还一直在运行,这时子进程就会变成孤儿进程, 它的ppid也变成了1,也就是被1号进程领养了,被回收了,从s+变成了s,也就是变成了后台进程,此时只能使用kill -9这个命令来杀掉。

int main()
{pid_t id = fork();if (id == 0){int cnt = 100;while (cnt){cout << "Im child, pid: " << getpid() << ", ppid: " << getppid() << endl;sleep(1);cnt--;}exit(0);}int cnt = 10;while (cnt){cnt--;cout << "Im father, pid: " << getpid() << ", ppid: " << getppid() << endl;sleep(1);}// wait(NULL);// cout<<"father wait child success....."<<endl;return 0;
}

 


6.进程优先级 

6.1基本概念

cpu资源分配的先后顺序,就是指进程的优先权(priority)。

优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能.。

 在一台计算机中,资源绝对是占多数,硬件绝对是占少数,所以要合理的安排进程,就需要给它们设置优先级。 

6.2查看系统进程

在linux或者unix系统中,用ps –l命令则会类似输出以下几个内容:

UID : 代表执行者的身份

PID : 代表这个进程的代号

PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号

PRI :代表这个进程可被执行的优先级,其值越小越早被执行

NI :代表这个进程的nice值

6.3 PRI and NI

PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高,PRI的范围是60-99,进程的默认PRI是80

那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值

PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为: PRI(new)=PRI(old)+nice

这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行所以,调整进程优先级,在Linux下,就是调整进程nice值

nice其取值范围是-20至19,一共40个级别

6.4 PRI vs NI

需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。

可以理解nice值是进程优先级的修正修正数据

6.5查看进程优先级的命令

6.5.1用top命令更改已存在进程的nice:

top

进入top后按“r”–>输 入进程PID–>输入nice值

7.其他概念

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发


今天的分享到这里就结束啦,感谢大家的阅读!

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

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

相关文章

一条龙-T检验+绘制boxplot

1.输入文件&#xff1a; 2.代码 #title:boxplot-5utr-cds-3tr-ATCG的百分比分布和T检验_封装函数版 rm(listls(allTRUE)) setwd("E:/R/Rscripts/5UTR_ABD_TE") library(tidyverse) library(ggplot2) # library(RColorBrewer) library(patchwork) library(dplyr) l…

Python-100-Days: Day01

Day01 Python简介 1.1989年Guido von Rossum在圣诞节之夜开始着手python语言编译器的编写。 2.1991年2月 Python v1 编译器诞生&#xff0c;使用C实现的&#xff0c;此时可以调用C的库函数。 3.1994年1月&#xff0c;Python v1.0 正式版发布。 4.2000年10月16日&#xff0…

新药品注册分类5大类的注册标准

在医药行业的浩瀚海洋中&#xff0c;药品注册分类就如同一座明亮的航标灯&#xff0c;指引着每一款新药从实验室走向市场&#xff0c;从理论概念变成患者手中的生命希望。本文将深入探讨化学药、中药、生物药的药品注册分类标准&#xff0c;药品分类常见问题、以及如何高效查询…

linux系统-深入学习文件系统与日志分析

目录 一、inode于block inode于block概括inode的内容inode包含文件的元信息用stat命令可以查看某个文件的inode信息Linux系统文件三个主要的时间属性目录文件架构 用户通过文件名打开文件时&#xff0c;系统内部的过程查看inode号码的实操硬盘分区后的结构 &#x1f447;用户访…

走向大规模应用之前,DePIN 如何突破技术、数据与市场之网

近期&#xff0c;随着分布式物理基础设施网络&#xff08;DePIN&#xff09;的快速演变&#xff0c;一个旨在利用区块链技术彻底改造传统基础设施模型的新兴生态系统正在逐渐浮现。2024 年 4 月&#xff0c;以 peaq 为代表的 DePIN 项目成功筹集了 1500 万美元用于生态系统的扩…

mac配置maven

在 macOS 上配置 Maven 也相对简单。以下是一种常用的方法&#xff1a; 1. 安装maven **下载 Maven&#xff1a;**首先&#xff0c;你需要从 Maven 官网&#xff08;https://maven.apache.org/download.cgi&#xff09;下载最新版本的 Maven。你可以选择二进制压缩包&#xf…

02.Scala简单演示

Scala创建对象的方法与Java有所不同 class可以直接传入形参&#xff1b; 形式为 变量名称&#xff1a;变量类型 逗号隔开 ** ** 方法定义也比较特殊 ** ** def方法名&#xff08;&#xff09;:返回值 { } 其中返回值Unit 等价于Java中的void

系统服务(22年国赛)—— 磁盘管理(压缩去重)

前言&#xff1a;原文在我的博客网站中&#xff0c;持续更新数通、系统方面的知识&#xff0c;欢迎来访&#xff01; 系统服务&#xff08;22年国赛&#xff09;—— 磁盘管理(压缩&&去重)https://myweb.myskillstree.cn/90.html 目录 StorageSrv 安装并创建vdo 将…

多输入多输出 | Matlab实现WOA-LSSVM鲸鱼算法优化最小二乘支持向量机多输入多输出预测

多输入多输出 | Matlab实现WOA-LSSVM鲸鱼算法优化最小二乘支持向量机多输入多输出预测 目录 多输入多输出 | Matlab实现WOA-LSSVM鲸鱼算法优化最小二乘支持向量机多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 Matlab实现WOA-LSSVM鲸鱼算法优化…

STL_vector源码剖析

STL vector STL2.91源码地址: https://github.com/lewischeng-ms/sgi-stl 侯捷老师用的是 2.91,不同版本的STL差异很大&#xff0c;靠后版本的STL用了太多typedef以及继承关系&#xff0c;导致可读性很差。 本文参考博客: https://blog.csdn.net/weixin_45389639/article/detai…

记账本React案例(Redux管理状态)

文章目录 整体架构流程 环境搭建 创建项目 技术细节 一、别名路径配置 1.路径解析配置&#xff08;webpack&#xff09; &#xff0c;将/解析为src/ 2.路径联想配置&#xff08;vsCode&#xff09;&#xff0c;使用vscode编辑器时&#xff0c;自动联想出来src文件夹下的…

python-excel自动化-openpyxl

openpyxl学习笔记 创建或打开表格存储和遍历数据设置单元格风格过滤器和排序更改工作表的背景颜色合并单元格冻结窗口数字格式公式图像图表条形图折线图散点图 创建或打开表格 # 创建 import datetime from openpyxl import Workbook # 实例化 wb Workbook() # 激活 work…

使用Excel生成sql脚本(insert/update/delete)

目录 前言 一、Excel文件脚本变量 二、操作示例 前言 在系统使用初期&#xff0c;存在某种原因&#xff0c;需要对数据库数据进行批量处理操作。往往都是通过制定Excel表格&#xff0c;通过Excel导入到数据库中&#xff0c;所以就弄一个excel生成sql的导入脚本&#xff0c;希…

探索设计模式的魅力:AI赋能分层模式,解构未来,智领风潮

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 探索设计模式的魅力&#xff1a;AI赋能分层模式&#xff0c;解构未来&#xff0c;智领风潮 ✨欢迎…

【网络安全】安全事件管理处置 — 安全事件处置思路指导

专栏文章索引&#xff1a;网络安全 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、处理DDOS事件 1.准备工作 2.预防工作 3.检测与分析 4.限制、消除 5.证据收集 二、处理恶意代码事件 1.准备 2.预防 3.检测与分析 4.限制 5.证据收集 6.消除与恢复 …

【Leetcode】vector刷题

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;Leetcode刷题 目录 1.只出现一次的数字2.杨辉三角3.删除有序数组中的重复项4.只出现一次的数字II5.只出现一次的数字III6.电话号码的字母组合 1.只出现一次的数字 题目链接&#xff1a;136.只出现一…

linux 编译opencv遇到问题

linux编译opencv4.8的时候遇到问题 Error: suffix or operands invalid for vpand看到很多说法是升级as这个工具的版本&#xff0c;自测是从2.20升级到2.27就可以了

python提取date的月份和天数

在Python编程中&#xff0c;经常需要从日期中提取月份和天数。这在数据处理、分析和可视化等领域都是非常常见的操作。 本文将介绍如何使用Python提取日期中的月份和天数&#xff0c;并通过代码示例展示具体的实现方法。 1.使用datetime模块获取日期信息 要提取日期的月份和天…

安卓手机连接电脑实用技巧:实现文件传输与共享

在手机使用过程中&#xff0c;我们常常需要将手机中的文件传输到电脑&#xff0c;或者将手机与电脑进行共享。为了实现这一需求&#xff0c;掌握一些实用的安卓手机连接电脑技巧就显得尤为重要。本文将为您详细介绍2种简单、高效且安全的方法&#xff0c;让您轻松实现安卓手机与…

【Python系列】受保护属性

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…