Linux(二)进程概念

news/2023/6/6 4:07:12

目录

一、冯诺依曼体系结构

二、操作系统

 三、进程概念

1、程序与进程的区别:

2、cpu分时机制

3、pcb——进程控制块

4、进程是什么?

四、进程状态

1、linux状态

2、僵尸态

pid_t fork(void):

fork创建进程之后,父子进程谁先运行?

僵尸进程

孤儿进程

 守护进程

五、fork()  创建一个子进程

1、返回值

2、创建子进程再认知

3、创建僵尸进程(滑稽)

4、当子进程成为僵尸进程时,父进程退出了!

5、僵尸进程如何进行处理?

6、孤儿进程

7、孤儿进程退出后会成为僵尸进程嘛?

六、环境变量

1、概念

2、优点

3、命令env

LS_COLOR颜色标记变量

 PATH路径变量

 4、其他指令

 七、环境变量的访问

 1、getenv()接口 :获取用来获取环境变量的值

 2、main函数参数

 打印argv运行参数:

打印env环境变量:

 3、全局变量 extern char **environ;


一、冯诺依曼体系结构

由冯.诺依曼提出来的关于计算机硬件体系结构:

输入设备:键盘

输出设备:显示器

存储器:内存

运算器&控制器:中央处理器-CPU

 CPU想要处理数据,是从内存中取出数据进行处理的,--CPU想要执行一个程序,第一件事就是先把程序从硬盘加载到内存中。

二、操作系统

本质:就是一个软件程序

功能:控制和管理计算机上的软硬件资源

目的:使计算机更加好久

完整的操作系统:内核+外部应用

我们所说的LInux就是Linux内核

计算机大体应用层次:用户->应用软件程序->系统调用接口->(操作系统)->驱动程序->硬件

 系统调用接口:操作系统内核向上提供的用于访问内核指定功能的接口

库函数: 就是对系统调用接口的进一步封装

库函数就是为了让这些系统调用接口在用户或者说程序员,让他们使用的时候更加容易

 三、进程概念

1、程序与进程的区别:

        程序是一堆指令集+数据 躺尸在硬盘上

        而进程是运行中的程序

 运行中的程序有很多,cpu应该先处理哪一个呢?

2、cpu分时机制

由操作系统进行控制管理,一个程序只在cpu上运行很短一段时间(一个时间片),然后切换到下一个程序,cpu处理每一个程序只会有一个时间片的时间,时间片运行完了就切换到下一个。

那如果是这样进行时间片轮转运行的,那么同一个程序cpu如何知道这个程序上次运行的情况呢?

3、pcb——进程控制块

操作系统需要对一个程序的运行状态进行描述(比如上次时间片轮转处理到哪个数据了)都要把cpu寄存器上的数据给保存下来,等到下次重新切换回来的时候,在把这些数据重新加载到寄存器上。

而这个对程序运行过程的描述,就叫做pcb——进程控制块,在linux下是一个task_struct结构体

操作系统调度管理程序运行就是通过pcb来实现的,那么之前的cpu分时机制也就可以正常运行了。

4、进程是什么?

进程是运行中的程序,这样回答很片面,因为这是站在用户的角度进行的描述。

在操作系统角度,进程就是系统对运行中程序动态运行过程的描述-PCB(进程控制快)

在linux下是一个task_struct结构体,系统通过这个描述实现对程序运行的管理及调度

四、进程状态

时间片:系统中cpu分时机制,让每一个程序只在cpu上执行一段很短的时间(时间片)

每一个运行中的程序,都应该有一个状态,该状态标记了一个进程该如何被系统进行调度运行

命令:ps -aux | grep loop :

ps -aux  是查看所有进程信息, grep是进行字符串匹配,

|管道符连接俩个命令(将前面命令结果交给后面来处理)

1、linux状态

前台进程&后台进程

前台进程就是指占据了一个终端的进程;

后台进程就是没有关联的进程,默默运行在系统中

下面的状态符号中    R+就表示前台运行态程序

①、运行态--R 正在被执行,以及拿到时间片就能执行的一种状态

②、可中断休眠态--S,一种阻塞态(因为某种运行条件不满足,而暂时不能被调度运行的进程状态,比如sleep(3))

③、不可中断休眠态--D:无法被中断打断阻塞,只能等待阻塞的唤醒条件满足后才能被调度执行

④、停止态--T:什么都不做(这跟休眠不一样,休眠是阻塞,停止还会被调度)

        小明是个植物人,还活着只是什么都不能做

⑤  僵尸态

2、僵尸态

进程退出了,但是资源没有完全被释放,等待处理的一种状态。

僵尸进程:处于僵尸态的进程,是一种退出了,但是资源没有完全被释放的进程

子进程先于父进程退出,然而父进程没有接收到子进程的返回值,所以子进程的资源不能完全释放。

pid_t fork(void):

        通过复制调用进程(父进程)来创建一个新的进程(子进程)

        返回值:在父进程中返回值是子进程的PID(大于0的值);在子进程中返回0,失败返回-1

站在系统角度进程就是pcb,在linux下是一个task_struct结构体

创建了一个进程出来,这个进程叫做子进程,它复制了父进程,里面的大部分数据都是从父进程pcb中复制过来的(内存指针、上下文数据……)

fork创建进程之后,父子进程谁先运行?

        答案:不一定,没有固定顺序,因为进程就是pcb,是系统用于进行程序运行调度管理的描述,相当于系统调度到谁就运行谁

僵尸进程

僵尸进程:子进程先于父进程退出,而父进程没有接收到子进程的返回值,导致子进程无法完全释放资源从而成为僵尸进程

危害:资源泄露(资源没有完全释放)

僵尸进程的避免:进程等待(等待子进程退出,获取退出子进程的返回值,释放子进程的资源,避免产生僵尸进程)

孤儿进程

产生:父进程先于子进程退出,子进程成为孤儿进程

特性:运行在后台,父进程成为1号进程(init进程)

孤儿进程退出后不会成为僵尸进程

孤儿进程没有危害,他会被init进程给接收

 守护进程

一种特殊的孤儿进程

长期运行在后台,不跟任何终端控制相关联

一般操作系统启动时候就启动,关闭的时候就关闭

五、fork()  创建一个子进程

fork函数通过系统调用结构创建了一个与原来进程几乎相同的进程(这个子进程pcb中信息和父进程几乎一致,包括内存指针、上下文数据……),两个进程可以做相同的事儿。

1、返回值

可以利用返回值不同来判断父子进程,进行代码分流,进入不同的分支

在父进程中返回子进程的pid(一个大于0的值)

在子进程中返回0

创建失败返回-1

  1 #include<stdio.h>2 #include<unistd.h>3 4 int main(){5     pid_t fpid;6     int count = 0;7     fpid = fork();8     if(fpid<0)9       printf("error in fork");10     else if(fpid == 0)11     {12       printf("i am the child process, my process id is %d", getpid());13       printf("我是儿子\n");14       count++;15     }16     else17     {18       printf("i am the parent process, my process id is %d", getpid());                    19       printf("我是爸爸\n");20       count++;21     }22     printf("统计结果是: %d\n", count);23     return 0;24 }

运行结果:

[dev@localhost fork]$ ./fork5
i am the parent process, my process id is 16866我是爸爸
统计结果是: 1
i am the child process, my process id is 16867我是儿子
统计结果是: 1

分析:

使用fork创建子进程,创建出一个pcb,里面存储的信息和父进程pcb中的信息几乎一致,保留的父进程运行的上下文数据、内存指针……

当创建子进程后,子进程走fpid==0的分支打印我是儿子,打印count为1

父进程走fpid>0的分支,打印我是爸爸,打印count为1

2、创建子进程再认知

    1 #include<stdio.h>2 #include<unistd.h>3 4 int main()5 {7   printf("hello world\n");8   pid_t ret = fork();9   printf("it's over!\n");                                                                10   return 0;11 }

运行结果:

        [dev@localhost fork]$ ./fork1
        hello world
        it's over!
        it's over!

分析

hello world运行一次,而over运行了俩次

当创建子进程之后,子进程pcb中的信息与父进程中的信息几乎一致,(内存指针、上下文数据……)父进程运行到第9行,子进程也保留父进程的运行上下文信息,也运行到第9行,所以父进程与子进程都打印了over代码。

3、创建僵尸进程(滑稽)

  1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 5 int main()6 {7     pid_t ret = fork();8     if(ret < 0){9       printf("error fork\n");10     }else if(ret == 0){11       printf("i am child\n");12       exit(0);// 子进程退出13     }14     else{15       printf("i am parent\n");16     }17     while(1)   // 能走到这里的只有父进程18     {19       sleep(3);20     }21     return 0;22 }           

上面代码在子进程分支中进行退出,产生僵尸进程,使用下方代码进行查看信息

ps -efl | head -n 1 && ps -efl | grep fork1

 PID 表示进程,PPID的值为父进程的PID,即第二行PID为18126的父进程为18125也就是第一行进程。由于子进程18126先于父进程退出,所以子进程状态为僵尸状态(Z)

 列序号    列含义    列含义说明
1    UID    用户标识ID
2    PID    进程ID
3.    PPID    父进程ID
4    C    CPU占用率
5    STIME    进程开始时间
6    TTY    启动此进程的TTY(终端设备)
7    TIME    此进程运行的总时间
8    CMD    完整的命令名(带启动参数)

 ps命令有一些参数:
-e : 显示所有进程
-f : 全格式
-h : 不显示标题
-l : 长格式
-w : 宽输出
a :显示终端上的所有进程,包括其他用户的进程。
r :只显示正在运行的进程。
u :以用户为主的格式来显示程序状况。
x :显示所有程序,不以终端机来区分。

4、当子进程成为僵尸进程时,父进程退出了!

那么这个子进程还存在吗?

使用kill命令杀死父进程18376

 

程序直接终止了,如果父进程退出了,子进程存在的意义也就没有了。

(子进程就是来给父进程服务的)

5、僵尸进程如何进行处理?

由上一个问题可以知道可以通过kill父进程来关闭僵尸子进程

进行进程等待

6、孤儿进程

  1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 5 int main()6 {7   printf("hello \n");8   pid_t ret = fork();9   if(ret < 0){10     printf("create error\n");11   }else if(ret == 0)12   {13     printf("i am child\n");14   }15   else16   {17     // 父进程先于子进程退出成为孤儿进程18     printf("i am parent\n");19     exit(0);20   }21   while(1)22   {23     sleep(3);                                                                            24     printf("i am %d\n",ret);25   }26   return 0;27 }

由下图可见父进程退出后,原来子进程的PPID变成了1号进程,即孤儿18591被1号进程所收养

下图中进程11971为子进程(一般子进程PID大于父进程PID)

它在第一次查看信息时(还没有关闭父进程)显示是S+(S+表示是一个前台进程)

 在第二次查看信息时(关闭父进程后)显示是S(成为了一个后台进程)后台进程的样子就是下方这个状态,不停地在打印  我是子进程这句话

7、孤儿进程退出后会成为僵尸进程嘛?

不会的,僵尸进程是因为在子进程退出时父进程没有接收子进程的返回值,而成为孤儿进程之后,子进程对应的父进程会变为1号进程init,1号进程是个特别负责任的父亲,如果孤儿进程退出了,1号进程会立即关闭它。所以孤儿进程退出不会成为僵尸进程。

六、环境变量

1、概念

所谓变量,就是保存着一个数据,环境变量:保存着当前运行环境参数的变量

2、优点

配置之后即时生效

让运行环境配置更加灵活

通过环境变量可以给运行中的程序传递数据

3、命令env

在终端使用env命令查看当前环境变量

LS_COLOR颜色标记变量

由于环境变量比较多,介绍几个了解就行,下面这个LS_COLORS变量,存储这关于ls命令查看文件颜色的一种变量(颜色标记)什么样的后缀名应该用什么样的颜色来显示

 PATH路径变量

在我们平常一段代码写好,编译之后进行运行的时候,都是在终端上敲入一段路径,比如我在当前路径下touch一个test文件,运行的时候输入 ./test 然而在我们之前的Linux指令中,却不需要这么多表示路径的操作,比如一个ls文件我在任何目录下都可以进行打开,然后查看当前目录文件操作,这就是PATH环境变量的作用,它使得其内部的文件在任何目录下都可以进行运行,PATH变量告诉编译器它里面存储的文件的文件检索地址,所以不需要通过人为的告诉编译器这个文件在哪里。

 4、其他指令

echo ${valuename}        打印指定内容(可以是变量内容)到终端显示

export        声明一个变量为环境变量

set        查看所有变量

unset        删除一个变量

 

 七、环境变量的访问

 1、getenv()接口 :获取用来获取环境变量的值

 

  1 #include<stdio.h>2 #include<stdlib.h>3 4 int main()5 {6     char *ptr = getenv("myvalue");                                                         7     {8       if(ptr != NULL)9         printf("%s\n",ptr);10     }11     return 0;12 }

 !gcc 重新编译上份代码

2、main函数参数

通常的main函数书写都为   int main()

其实它也是有参数的  

int main(int argc, char* argv[], char* env[])

 argc 保存参数个数,argv保存参数名,env参数保存着环境变量

 打印argv运行参数:

  1 #include<stdio.h>2 #include<stdlib.h>3 4 int main(int argc, char* argv[])5 {6     for(int i = 0; i < argc; i++)7     {8       printf("argv[%d]:%s\n", i, argv[i]);9     }10     return 0;11  }                                                                                      

打印env环境变量:

  1 #include<stdio.h>2 #include<stdlib.h>3 4 int main(int argc, char* argv[], char* env[])5 {6     for(int i = 0; i < argc; i++)7     {8       printf("argv[%d]:%s\n", i, argv[i]);9     }10     for(int i = 0; env[i] != NULL; i++)11     {12       printf("env[%d]:%s\n",i, env[i]);                                                    13     }21     return 0;22 }

 除了上方的运行参数,还有所有的全局变量

 3、全局变量 extern char **environ;

  1 #include<stdio.h>2 #include<stdlib.h>3 4 int main()5 {6     extern char**environ;7     for(int i = 0; environ[i] != NULL; i++)8     {9       printf("environ[%d]:%s\n",i, environ[i]);                                            10     }11     return 0;12 }

 

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

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

bochs安装配置

玄学bochs安装配置记录一波 系统&#xff1a;Ubuntu 16.04/64位bochs版本&#xff1a;bochs-2.6.9 安装步骤 第1步&#xff1a;bochs下载&#xff1a;下载地址第2步&#xff1a;解压下载的源代码 sudo tar zxvf bochs-2.6.9.tar.gz 第3步&#xff1a;进入bochs-2.6.8目录&…

bochs在安卓上模拟kali linux系统

概述 本文将介绍如何在安卓手机上安装并运行Kali系统&#xff0c;我们可以使用Kali系统来破解Wifi密码&#xff0c;当然它的功能远不止于此&#xff0c;它还有非常强大而且实用的功能&#xff0c;同时Kali系统对硬件配置要求并不高&#xff0c;如果你身边有很久不用的旧手机那…

基于OpenCv的人脸识别,翻车了居然识别错误。

前言 我们身边的人脸识别有车站检票&#xff0c;监控人脸&#xff0c;无人超市&#xff0c;支付宝人脸支付&#xff0c;上班打卡&#xff0c;人脸解锁手机。 人脸检测是人脸识别系统组成的关键部分之一&#xff0c;其目的是检测出任意给定图片中的包含的一个或多个人脸&#xf…

聚焦儿童羽绒服产业,看用友YonSuite打造领先实践的数智创新小灯塔

有一种冷“是妈妈觉得你冷”。每每想起小时候&#xff0c;为了应对寒冷的冬季&#xff0c;都会“全副武装”&#xff0c;裹得厚厚的&#xff0c;里三层外三层。 放到如今&#xff0c;有了羽绒服的萌娃们&#xff0c;已不再像我们当年一样穿得厚厚的了。现在的年轻爸妈喜欢装扮…

AtCoder Beginner Contest 165 (C(暴力),D(数学推导)E(思维),F(树上LIS))

题目链接 C - Many Requirements 如何计算这种序列有多少个呢&#xff1f; 我们可以将此转化为在长度为 n的序列上划分成 m 个段&#xff0c;由于有些数字可能没被选上 我们补上m个数&#xff0c;然后每种数至少选一次。根据隔板法原理&#xff0c;数列的个数为 C(nm−1,m−1) …

excel表格分割线一分为二_PDF转Excel的Python代码

本代码由广州75中麻玉国老师分享在NOI教练群内&#xff0c;自己亲测了一下&#xff0c;感觉蛮好玩&#xff0c;所以特意收藏下来&#xff0c;具体代码如下&#xff1a;import pdfplumberfrom openpyxl import Workbookwb Workbook() # 创建文件对象ws wb.active # 获取第一…

layui table 每列加标签_【前端】layui表格中根据条件给对应的列加背景色

【前端】layui表格中根据条件给对应的列加背景色【前端】layui表格中根据条件给对应的列加背景色1.效果(根据条件动态给表格加背景色)2.代码:在我自己的项目中&#xff0c;由于条件比较多&#xff0c;提取出了一个方法 getColor(that,item,index); 代码的示例中写出了其中一条d…

复杂表格巧拆分(转)

复杂表格巧拆分(转)实际工作中&#xff0c;我们有时会遇到一些复杂表格&#xff0c;由于受到软件功能的限制&#xff0c;制作起来有一定难度。当你被这些复杂表格弄得焦头烂额之际&#xff0c;有没有想到过另僻蹊径呢&#xff1f;下面&#xff0c;我们就通过一个例子来说明在如…