Linux进程一【进程概念、进程状态、进程优先级、环境变量】

本文详细介绍了冯诺依曼体系结构下计算机硬件组件及其功能,深入解析了操作系统的概念、目的及组成部分,包括内核、其他程序、系统调用和库函数。此外,还探讨了进程的概念、描述方式、状态、优先级以及进程间通信,提供了丰富的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

冯诺依曼体系结构

计算机都是由一个个硬件组件组成:
  • 输入设备:键盘、鼠标等
  • 输出设备:显示器、打印机
  • 存储器:内存
  • 中央处理器(CPU):运算器、控制器组成

ps:不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备) ;外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取;所有设备都只能直接和内存打交道。硬件结构决定软件行为,所有设备都是围绕存储器工作的。

操作系统

概念:

操作系统是管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的内核与基石。笼统的理解,操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)
  • 其他程序(例如函数库,shell程序等)
目的:
  • 与硬件交互,管理所有的软硬件资源
  • 为用户程序(应用程序)提供一个良好的执行环境
定位:
  • 搞管理的软件
管理方法:
  1. 先描述起来:用 struct 结构体
  2. 在组织起来:用链表或者其他高效的数据结构
系统调用和库函数:
  • 操作系统对外会表现为一个整体,但是会暴露自己的部分接口供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,库函数封装了系统调用接口,从而形成库,有了库就很有利于更上层用户或者开发者进行二次开发。

进程介绍

进程概念:

进程就是一个运行中的程序,对于操作系统来说进程就是一个PCB,这个PCB是一个进程控制块,它是一个运行中程序的描述,操作系统通过这个PCB的描述来控制程序的运行。在Linux下这个PCB实际上是一个结构体 task_struct,如何查看这个结构体?
在这里插入图片描述
大概在文件 sched.h 中 1342 行附近。

进程如何描述一个运行中的程序?
  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针 。
  • 上下文数据: 进程执行时处理器的寄存器中的数据
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息
查看进程
  • 进程的信息可以通过 /proc 系统文件夹查看。举例:如果要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹。
    在这里插入图片描述
  • 通过 ps 指令来查看进程,ps命令用于报告当前系统的进程状态。可以搭配kill指令随时中断、删除不必要的程序。ps命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。
    在这里插入图片描述
    ps -aux:在这里插入图片描述
    ps -ef:
    在这里插入图片描述
通过系统调用创建进程
  • pid_t fork(void);
    在这里插入图片描述
    父子进程代码共享,数据各自开辟空间是独有的。(采用写时拷贝技术)

  • 代码举例:

#include <stdio.h> 
#include <unistd.h> 
int main() 
{    
  int ret = fork();    
  if(ret < 0)
  {        
    perror("fork");        
    return 1;     
  }    
  else if(ret == 0)
  { //child        
    printf("I am child : %d, ret: %d\n", getpid(), ret);     
  }
  else
  { //father        
    printf("I am father : %d, ret: %d\n", getpid(), ret);     
  }    
  sleep(1);    
  return 0;  
}
进程状态
  • R: 运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

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

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

  • T:停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可 以通过发送 SIGCONT信号让进程继续运行。PS:在某一程序运行时,输入 CTRL+Z(让进程停止,并不是让进程退出) 可以使该进程变为 T 状态的进程。

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

  • Z:僵死状态(zombie):进程已经退出,但是资源没有完全释放。

    僵尸进程
    • 产生原因:子进程先于父进程退出,为了保存退出原因,因此资源并没有完全释放。因此在子进程退出时,操作系统会通知父进程,让父进程获取子进程的退出原因,然后释放子进程的所有资源。如果父进程当前并没有关注子进程的状态,则子进程将会成为僵尸进程
    • 僵尸进程的危害:进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程)可父进程如果一直不读取,那子进程就一直处于Z状态,维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,也就是说,Z状态一直不退出,PCB一直都要维护,所以才会造成内存资源的泄漏。
    • 僵尸进程的避免:进程等待
    • 僵尸进程的处理:退出父进程
    孤儿进程
    • 产生原因:父进程先于子进程退出,子进程成为孤儿进程,运行在后台。此时,孤儿进程被1号 init 进程领养,他的父进程成为1号进程(init进程)。PS:此时孤儿进程退出不会成为僵尸进程
    守护进程/精灵进程
    • 它是一个特殊的孤儿进程,在孤儿进程的基础上,脱离终端、脱离登录会话,通常运行在后台默默地工作,不希望受到终端会话的影响。
进程优先级
  • 在Linux下,用 ps –fl 命令查看进程会出现以下:
    在这里插入图片描述
    PR I就是进程的优先级,此值越小,进程的优先级别越高 、此值越大,进程的优先级别越低。NI 就是 nice 值,其表示进程可被执行的优先级的修正数。PRI 值越小越快被执行,那么加入 nice 值后,将会使得PRI变为:PRI(new)=PRI(old)+nice 。在 Linux 下,调整进程优先级就是调整 nice。nice其取值范围是-20至19,一共40个级别。PS:进程的 nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进 程的优先级变化

  • 指令设置进程优先级

    原来 优先级:在这里插入图片描述
    指令:
    ①:renice -n 10 -p 3169 或者 nice -n 10 ./test(test 为可执行文件)
    在这里插入图片描述
    ②:输入top指令–>进入top后按“r”–>输入进程PID–>输入nice

PS:将优先级升高(即将nice值减小时),需要 root 权限。
在这里插入图片描述

环境变量

概念:
  • 存放系统运行环境参数的变量
相关指令:
  • env:显示所有环境变量
    在这里插入图片描述
  • echo:显示某个环境变量值(使用时需要加上$符号)
    在这里插入图片描述
    其中在 /usr/bin 目录下存放的是指令:比如 ls 、pwd 、cp、mv 等等
  • set:显示本地定义的shell变量和环境变量
  • export: 设置一个新的环境变量
  • unset:清除环境变量
    在这里插入图片描述
常见环境变量:
  • PATH : 指定命令的搜索路径
    为什么有些指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行? 可以将二进制程序放到环境变量PATH当中的路径中,我这样子做就可以不用带路径执行程序:
    在这里插入图片描述
    也可以将我们的程序所在路径加入环境变量PATH当中:
    在这里插入图片描述

  • HOME : 指定用户的主工作目录(就是用户登陆到Linux系统中时默认的目录)

  • SHELL : 当前Shell,它的值通常是 /bin/bash

通过代码获取环境变量:
  • 命令行第三个参数获取
#include <stdio.h> 
int main(int argc, char *argv[], char *env[]) 
{    
	int i = 0;    
	for(i; env[i]; i++)
	{       
		printf("env[%d] = %s\n",i,env[i]); 
	}    
    return 0;
 }
  • 通过第三方变量environ获取
#include <stdio.h> 
int main(int argc, char *argv[], char *env[]) 
{    
    //libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明
	extert char** environ;
	int i = 0;   
	for(i; environ[i] != NULL; i++)
	{       
		 printf("environ[%d] = %s\n",i,environ[i]);
	}    
    return 0;
 }
通过系统调用获取( getenv)或 设置( putenv )环境变量的内容 :
  • getenv:通过环境变量名称获取内容,用 getenv 函数可以通过给出 name 来获得 value 的值。
    在这里插入图片描述
   26    //char* getenv(const char* name); name:想要获取的环境变量名
   27   //通过环境变量名称获取内容
   28   char* ptr = getenv("PATH");
   29   if(ptr == NULL)
   30   {
   31     printf("have no PATH\n");
   32   }
   33   else
   34   {
   35     printf("PATH=%s\n",ptr);
   36   }
   37   return 0;
   38 }       
  • putenv:用来改变或增加环境变量的内容,如果环境表中没有 name 这个环境变量,则添加该环境变量;如果环境表中已经有了name这个环境变量,则先删除之前的 value,再修改为新的 value。
    在这里插入图片描述
#include<stdio.h>
#include<stdlib.h>
int main()
{
   int ret = putenv("MYTEST=123");
   if(ret != 0)
   {
  	 printf("putenv error!\n");
   }
   else
   {
     printf("putenv complete!\n");
   }
   return 0;
}
环境变量的特性与作用
  • 环境变量通常具有全局属性,可以被子进程继承下去。
#include <stdio.h> 
#include <stdlib.h> 
int main() 
{    
	char* env = getenv("MYENV");    
	if(env)
    {        
   	   printf("MYENV=%s\n", env);
    }    
    return 0; 
} 

直接查看,发现没有结果,说明该环境变量根本不存在,导出环境变量 export MYENV="hello world"再次运行程序,输出 MYENV=hello world。

  • 环境变量可以让系统运行环境参数配置起来更加灵活。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值