Linux(二)进程概念

目录

一、冯诺依曼体系结构

二、操作系统

 三、进程概念

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     else
 17     {
 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   else
 16   {
 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 }

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值