【Linux系统编程】第二十弹---进程优先级 命令行参数 环境变量
✨个人主页: 熬夜学编程的小林
💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】
目录
1、进程优先级
2.1、什么是优先级
2.2、优先级的描述
2.3、优先级与权限的关系
2.4、为什么要有优先级
2.5、Linux优先级的特点
2.6、其他概念
2、命令行参数
3、环境变量
3.1、基本概念
3.2、PATH环境变量
3.3、其他环境变量
1、进程优先级
2.1、什么是优先级
指定进程获取某种资源(CPU)的先后顺序。
2.2、优先级的描述
进程优先级的描述跟进程状态描述类似,实质是在task_struct(内存控制块)结构体内部有一个描述优先级的属性,通过数字表示先后顺序。Linux 中优先级数字越小,优先级越高。
2.3、优先级与权限的关系
权限决定能不能获取资源。
优先级决定获取资源的顺序,已经能获取资源。
2.4、为什么要有优先级
进程访问的资源(CPU)始终是有限的。系统中进程大部分情况都是比较多的。
操作系统关于调度和优先级的原则:分时操作系统,基于时间片进行调度,保证基本的公平。如果进程因为长时间不被调度,就造成了饥饿问题。
2.5、Linux优先级的特点
在讲解优先级特点之前,我们先通过一个C语言程序查看优先级。
C语言代码
#include<stdio.h>
#include<unistd.h>int main()
{while(1){printf("I am a process,pid:%d\n",getpid());}return 0;
}
命令行代码
ps -al // 查看所有进程信息
测试结果
我们很容易注意到其中的几个重要信息,有下:
UID : 代表执行者的身份。
PID : 代表这个进程的代号。
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号。
PRI :代表这个进程可被执行的优先级,其值越小越早被执行。
NI :代表这个进程优先级的修正数据,nice值,新的优先级 = 默认优先级 + nice,达到对于进程优先级动态修改的过程。
调整优先级
nice/renice 调整优先级
此处博主使用top命令调整优先级。
- 输入top命令
- 进入top后按“r”–>输入进程PID–>输入nice值

测试一
我们将nice值改为100,现象如下:

可以看到 NI 只修改为了19,PRI修改为了99。表名nice值并不能任意调整,而是有范围的。 范围是 [-20,19] ,共40个数字。
测试二
我们将nice值改为-10,现象如下:

我们可以看到,当我们第二次修改nice值时,不允许我们修改,因为修改优先级是有风险的,如果强制需要修改nice值,我们只需要切换成root账号即可。
测试三
使用root账号将nice值改为-10,现象如下:

我们可以看到NI修改成了-10,PRI修改成了70,我们刚刚的PRI是99,将nice值修改为-10,为什么现在的PRI为70了呢?原因是 每次调整优先级都是从80开始的。新的优先级 = 默认优先级 + nice,70 = 80 - 10。
测试四
使用root账号将nice值改为-100,现象如下:

可以看到NI被修改为-20,因此能够证明nice的最小值为-20,且新的优先级 = 默认优先级 + nice,60 = 80 - 20。
2.6、其他概念
- 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
- 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
- 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
- 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
2、命令行参数
写C语言代码中,main函数也是函数,可以带参数?
答案是可以带参数也可以不带参数,下面就使用带参数的main函数演示。
代码演示
#include<stdio.h>// 命令行参数测试
int main(int argc,char* argv[])
{int i = 0;for(i=0;i<argc;i++){printf("argv[%d] = %s\n",i,argv[i]);}return 0;
}
测试结果

通过上图现象我们可以看到argc是元素个数,argv是一个边长数组,猜测数组以NULL结尾。
验证数组以NULL结尾
#include<stdio.h>int main(int argc,char* argv[])
{int i = 0;// argv[i]为假则循环结束for(i=0;argv[i];i++){printf("argv[%d] = %s\n",i,argv[i]);}return 0;
}
测试结果

为什么要有命令行参数?
本质:命令行参数本质是交给我们程序的不同选项,用来定制不同的程序功能。命令中会携带很多选项。
命令行中启动的程序是谁干的?
命令行中启动的程序,都会变成进程,且都是bash的子进程,因此是bash(命令行解释器)干的。
代码演示一
#include<stdio.h>
#include<unistd.h>int g_val = 10000;
int main()
{printf("I am parent process,g_val:%d,pid:%d,ppid:%d\n",g_val,getpid(),getppid());sleep(5);pid_t id = fork();if(id == 0){while(1){printf("I am child process,g_val:%d,pid:%d,ppid:%d\n",g_val,getpid(),getppid());sleep(1);}}else{printf("I am parent process,g_val:%d,pid:%d,ppid:%d\n",g_val,getpid(),getppid());sleep(1);}return 0;
}

父进程的数据,默认能被子进程看到并访问。
代码演示二
#include<stdio.h>
#include<unistd.h>
#include<string.h>int g_val = 10000;
int main(int argc,char* argv[])
{printf("I am parent process,g_val:%d,pid:%d,ppid:%d\n",g_val,getpid(),getppid());if(argc != 2){printf("Usage: %s -[a,b,c,d]\n", argv[0]);return 1;}if(strcmp(argv[1], "-a") == 0){printf("this is function1\n");}else if(strcmp(argv[1], "-b") == 0){printf("this is function2\n");}else if(strcmp(argv[1], "-c") == 0){printf("this is function3\n");}else if(strcmp(argv[1], "-d") == 0){printf("this is function4\n");}else{printf("no this function!!\n");}return 0;
}
测试结果

命令行中启动的程序,都会变成进程,且都是bash的子进程。启动程序,默认是输入给父进程bash(命令行解释器)的!!!
3、环境变量
3.1、基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
3.2、PATH环境变量
基本认知
执行命令和运行自己写的程序是没有区别的,且Linux中70% 的命令是C语言写的。
为什么执行ls这些系统提供的命令可以不带路径,而我们自己写的C语言程序需要加./(带路径)呢?
Linux系统重存在一些全局的设置,表明告诉命令行解释器应该去哪个路径下去寻找可执行程序,当执行ls命令(可执行程序在/usr/bin目录中)时,会先去找ls对应的可执行程序,默认去PATH中找。
查看PATH内容

通过echo $PATH 获取PATH(环境变量)内容 ,类似*p。
补充:
- 系统中很多的配置,在我们登录Linux系统的时候,已经被加载到了bash进程中(内存)。
- bash在执行命令的时候,需要先找到路径(默认去PATH中找),因为未来要加载。
如果我们想像系统指令一样执行自己写的可执行程序,怎么做?
方式一(粗暴):直接将我们的可执行程序拷贝到PATH的其中一个路径(例如/usr/bin)中。
注意:拷贝内容到PATH环境中需要配root权限,此处使用sudo提权。
sudo cp myprocess /usr/bin # 此处的/usr/bin也可以是PATH中的其他路径

不建议使用这种方式,因此下面我们将该可执行程序在/usr/bin中的内容删除。
sudo rm /usr/bin/myprocess

方式二(温柔):把可执行程序路径增加到PATH环境变量中。
错误示范:
PATH=/home/jkl/path # 将可执行程序的当前目录赋值给PATH变量,会直接覆盖PATH

环境变量直接被我们新的路径覆盖了怎么办呢?
其实很简单,直接将系统关闭,重进系统就可以了。因为我们上面说了 系统中很多的配置,在我们登录Linux系统的时候,已经被加载到了bash进程中(内存)。
我们重新登录系统之后,发现环境变量回来了,且不能直接执行我们写的可执行程序了。

正确示范:
PATH=$PATH:/home/jkl/path # 将原本的PATH路径以及我们可执行程序当前目录赋值给PATH
演示结果

PATH环境变量是Linux系统中搜索可执行程序的默认路径,也是which指令搜索路径的默认路径。
PATH环境变量的路径是内存级别的,重新登录系统又会变成默认路径,怎样让追加的环境变量路径永久存在呢?
最开始的环境变量不是在内存中,而是在系统对应的配置文件中,在我们登录系统时,会创建一个bash进程,bash进程会读取配置文件,然后把配置文件的环境变量(包括PATH)在自己的bash进程拷贝一份。
这个配置文件在哪里?
vim .bash_profile
vim .bashrc
vim /etc/bashrc
我们的PATH配置文件可能在.bash_profile或者.bashrc中。博主的在.bashrc中。

想要登录时每次都默认执行自己写的可执行程序,把可执行程序路径加到环境变量的配置文件里面即可,如下图:

加上该路径之后,myprocess可以像系统命令(ls)一样,在任意目录中使用了,且无需加./。
Windows也有环境变量,我们在安装jdk或者python时一般需要配置环境变量。
3.3、其他环境变量
env : 查看系统所有的环境变量

history :查看历史命令

HOME : 家目录所在的环境变量
PWD : 当前目录路径变化
SHELL : 当前Shell,它的值通常是/bin/bash。
HISTSIZE : 历史命令个数 上翻下翻 Linux默认会记录最新的1000条命令

自己定义一个环境变量:
export THIS_IS_MY_ENV=hellolinux 导入环境变量(不加export,依旧存在变量,本地变量)
unset THIS_IS_MY_ENV 取消环境变量
export测试

疑问:export 也是一个命令,命令就会创建子进程,子进程就应该不被bash看到,为什么却能将变量导入到环境变量中。?
80% 命令都是bash创建子进程执行的 ,称为普通命令。还有20%命令,如(export / echo) 由bash亲自执行的,称为内建命令。
怎么证明真的有内建命令呢?

通过上面实验,我们可以证明确实有内建命令。
普通测试

- 本地变量只在bash内部有效,无法被子进程继承下去。导成环境变量才能被获取。
- 用本地变量理解内建命令。内建命令可以查到本地变量。
- echo能够打印本地变量(子进程无法获取)也能够证明echo是内建命令。
注意:已经存在的本地变量导成环境变量,只需要使用export 变量名即可。
能否通过C语言程序查看环境变量呢?
答案是可以的,在写程序之前我们需要查一下手册,man environ,environ为查看全局的指针变量。

C语言程序
#include<stdio.h>
#include<unistd.h>
int main()
{extern char** environ;// 声明外部文件变量int i=0;for(i=0;environ[i];i++)// environ[i]为假则循环结束{printf("env[%d]->%s\n",i,environ[i]);}return 0;
}
测试结果

测试结果与使用命令env的结果是一样的。 说明环境变量默认也是可以被bash子进程拿到的。环境变量们,默认在bash内部。
环境变量有很多,bash内部是如何组织的?
通过上面的C语言代码我们大概可以推断,环境变量的组织与命令行参数类似,是通过一个变长数组组织的,最后一个数据以NULL结尾。
main函数带参的C语言程序
#include<stdio.h>
#include<unistd.h>
int main(int argc,char* argv[],char* env[])
{int i = 0;for(i=0;env[i];i++){printf("env[%d]->%s\n",i,env[i]);}return 0;
}
测试结果

bash进程启动的时候,默认会给子进程形成argv[]命令行参数表(用户输入的命令行来),env[]环境变量表(从OS的配置文件来),bash通过各种方式交给子进程。
补充:
- 导环境变量的本质:把字符串添加到环境变量表中。
- 环境变量具有系统级的全局属性,因为环境变量会被子进程继承下去。
获取环境变量方法:
- extern char** environ;
- main函数参数
- getenv("path");
man getenv

代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char* argv[],char* env[])
{char* path = getenv("PATH");if(path == NULL) return 1;printf("psth:%s\n",path);return 0;
}
测试结果

putenv(); // 创建环境变量
相关文章:
【Linux系统编程】第二十弹---进程优先级 命令行参数 环境变量
✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、进程优先级 2.1、什么是优先级 2.2、优先级的描述 2.3、优先级与权限的关系 2.4、为什么要有优先级 2.5、Linux优先级的…...
无人机之4G模块的主要功能和优势
一、增强图传 在无人机飞行过程中,传统的图传方式可能会受到信号遮挡或干扰的影响,导致图像传输不稳定甚至中断。而4G模块通过结合4G网络技术,能够在原有图传技术的基础上提供增强的图传功能。当传统图传信号不佳时,无人机可以自动…...
深度学习-03 Pytorch
损失函数是用来衡量模型预测结果与真实值之间的差异,并用来优化模型的指标。在机器学习和神经网络中,常用的损失函数包括均方误差(Mean Squared Error,MSE)、交叉熵(Cross-Entropy)等。 反向传播…...
GRU(门控循环单元)的原理与代码实现
1.GRU的原理 1.1重置门和更新门 1.2候选隐藏状态 1.3隐状态 2. GRU的代码实现 #导包 import torch from torch import nn import dltools#加载数据 batch_size, num_steps 32, 35 train_iter, vocab dltools.load_data_time_machine(batch_size, num_steps)#封装函数&…...
【医疗大数据】医疗保健领域的大数据管理:采用挑战和影响
选自期刊**《International Journal of Information Management》**(IF:21.0) 医疗保健领域的大数据管理:采用挑战和影响 1、研究背景 本研究的目标是调查阻止医疗机构实施成功大数据系统的组织障碍,识别和评估这些障碍,并为管理…...
gevent + flask 接口会卡住
在使用 gevent 和 Flask 处理 CPU 密集型任务时,确实可能会遇到性能瓶颈。这是因为 gevent 主要优化的是 I/O 密集型任务,而不是 CPU 密集型任务。以下是一些可能的原因和解决方案: 原因 Gevent 的协程模型: gevent 使用 greenle…...
SpringCloud Alibaba五大组件之——Sentinel
SpringCloud Alibaba五大组件之——Sentinel(文末附有完整项目GitHub链接) 前言一、什么是Sentinel二、Sentinel控制台1.下载jar包2.自己打包3.启动控制台4.浏览器访问 三、项目中引入Sentinel1.在api-service模块的pom文件引入依赖:2.applic…...
brpc之io事件分发器
结构 #mermaid-svg-v4SjrdGXadMO4udP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-v4SjrdGXadMO4udP .error-icon{fill:#552222;}#mermaid-svg-v4SjrdGXadMO4udP .error-text{fill:#552222;stroke:#552222;}#merm…...
MySQL | 知识 | 从底层看清 InnoDB 数据结构
文章目录 一、InnoDB 简介InnoDB 行格式COMPACT 行格式CHAR(M) 列的存储格式VARCHAR(M) 最多能存储的数据记录中的数据太多产生的溢出行溢出的临界点 二、表空间文件的结构三、InnoDB 数据页结构页页的概览Infimum 和 Supremum使用Page Directory页的真实面貌 四、B 树是如何进…...
es的封装
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、类和接口介绍0.封装思想1.es的操作分类 二、创建索引1.成员变量2.构造函数2.添加字段3.发送请求4.创建索引总体代码 三.插入数据四.删除数据五.查询数据 前…...
写一个自动化记录鼠标/键盘的动作,然后可以重复执行的python程序
import sys import threading import time from PyQt5.QtWidgets import * from auto_fun import * import pyautogui import pynput from PyQt5.QtCore import pyqtSignal from MouseModule import * from pynput import keyboardlocal_list [] # 保存操作坐标、动作、文本 …...
Spring Boot-热部署问题
Spring Boot 热部署问题分析与解决方案 热部署(Hot Deployment)是指在应用程序运行过程中,无需停止应用就可以动态加载新代码、配置或资源,从而提升开发效率。在 Spring Boot 开发中,热部署是一项非常实用的功能&…...
深度学习——管理模型的参数
改编自李沐老师《动手深度学习》5.2. 参数管理 — 动手学深度学习 2.0.0 documentation (d2l.ai) 在深度学习中,一旦我们选择了模型架构并设置了超参数,我们就会进入训练阶段。训练的目标是找到能够最小化损失函数的模型参数。这些参数在训练后用于预测&…...
芯片验证板卡设计原理图:372-基于XC7VX690T的万兆光纤、双FMC扩展的综合计算平台 RISCV 芯片验证平台
基于XC7VX690T的万兆光纤、双FMC扩展的综合计算平台 RISCV 芯片验证平台 一、板卡概述 基于V7的高性能PCIe信号处理板,北京太速科技板卡选用Xilinx 公司Virtex7系列FPGA XC7VX690T-2FFG1761C为处理芯片,板卡提供两个标准FMC插槽,适用于…...
【软设】 系统开发基础
【软设】 系统开发基础 一.软件工程概述 (了解一下大概的流程就行) 1. 可行性分析与项目开发计划 目的:评估项目的经济性、技术性和运营性,判断项目是否值得投资和开发。确定开发时间、预算、所需资源等。 可行性分析ÿ…...
Linux移植之系统烧写
直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81 本文仅作为个人笔记使用,方便进一步记录自己的实践总结。 前面我们已经移植好了 uboot 和 linux kernle,制作好了根文件系统。但是我们移植都是通过网络来测试的,在实际的产品开发中…...
【数据结构与算法】LeetCode:双指针法
文章目录 LeetCode:双指针法正序同向而行(快慢指针)移除元素移动零(Hot 100)删除有序数组中的重复项颜色分类(Hot 100)压缩字符串移除链表元素删除排序链表中的重复元素删除排序链表中的重复元素…...
Istio下载及安装
Istio 是一个开源的服务网格,用于连接、管理和保护微服务。以下是下载并安装 Istio 的步骤。 官网文档:https://istio.io/latest/zh/docs/setup/getting-started/ 下载 Istio 前往Istio 发布页面下载适用于您的操作系统的安装文件,或者自动…...
Redis基础数据结构之 Sorted Set 有序集合 源码解读
目录标题 Sorted Set 是什么?Sorted Set 数据结构跳表(skiplist)跳表节点的结构定义跳表的定义跳表节点查询层数设置 Sorted Set 基本操作 Sorted Set 是什么? 有序集合(Sorted Set)是 Redis 中一种重要的数据类型,…...
蓝队技能-应急响应篇Web内存马查杀JVM分析Class提取诊断反编译日志定性
知识点: 1、应急响应-Web内存马-定性&排查 2、应急响应-Web内存马-分析&日志 注:传统WEB类型的内存马只要网站重启后就清除了。 演示案例-蓝队技能-JAVA Web内存马-JVM分析&日志URL&内存查杀 0、环境搭建 参考地址:http…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
