【Linux系统编程】第二十弹---进程优先级 命令行参数 环境变量

news2024/9/21 20:29:43

个人主页: 熬夜学编程的小林

💗系列专栏: 【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(); // 创建环境变量

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

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

相关文章

【产品更新】中汇保函及汇匠源保证金保函平台

中汇保函 新增 1.新增小程序查询验证功能&#xff0c;手机输入即可查验。 2.新增小程序客户案例案例&#xff0c;合作单位及案例展示页面。 3.履约保函、预付款保函、质量保函、工程款支付保函订单提交及订单状态查验。 4.PC产品官网已经上线&#xff0c;可随时访问了解产品介…

【Java】synchronized 基础线程安全

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; 在多线程编程中&#xff0c;线程安全是一个至关重要的概念。Java 提供了多种机制来处理线程安全问题&#xff0c;其中 synchronized 关键字是最常用和最基础的一种。本文将介绍线程安全问题的原因&a…

智创未来,景联文科技提供全方位数据采集服务

随着科技的日新月异&#xff0c;人工智能技术正在改变我们的生活与工作方式&#xff0c;数据成为推动人工智能&#xff08;AI&#xff09;技术发展的基石。 高质量的数据对于训练机器学习模型、提升算法性能以及实现智能应用的广泛部署至关重要。 景联文科技凭借卓越的技术实力…

Android14请求动态申请存储权限

Android14请求动态申请存储权限 Android14和Android15存储权限有增加多了选择部分&#xff0c;还是全部。一个小小的存储权限真的被它玩出了花来。本来Android13就将存储权限进行了3个细分&#xff0c;是图片&#xff0c;音频还是视频文件。 步骤一&#xff1a;AndroidManife…

六种主流ETL工具的比较与Kettle的实践练习指南--MySQL、hive、hdfs等之间的数据迁移

在数据集成和数据仓库建设中&#xff0c;ETL&#xff08;Extract, Transform, Load&#xff09;工具扮演着至关重要的角色。本文将对六种主流ETL工具进行比较&#xff0c;并深入探讨Kettle的实践应用。 一、六种主流ETL工具比较 1. DataPipeline 设计及架构&#xff1a;专为…

Python异常处理:自定义异常②

文章目录 1. 什么是自定义异常&#xff1f;2. 为什么需要自定义异常&#xff1f;3. 如何定义自定义异常&#xff1f;3.1 基本自定义异常3.2 带详细信息的自定义异常3.3 自定义异常的继承层次 4. 使用自定义异常4.1 抛出自定义异常4.2 捕获自定义异常 5. 自定义异常的应用场景5.…

【C++】透析string类

个人主页&#xff1a;CSDN_小八哥向前冲~ 所属专栏&#xff1a;C入门 目录 string类介绍 auto和范围for auto关键字 范围for string类常用接口说明 string类常见构造 string类容量操作 string类的访问及遍历操作 string类修改操作 string的结构说明 vs下的结构 G下的…

LibJPEG库使用_通过LibJPEG将RGB数据保存为JPG图片存储到磁盘

一、前言 LibJPEG库是一个广泛使用的开源C库&#xff0c;用于处理JPEG图像的压缩和解压缩。该库由独立JPEG小组&#xff08;Independent JPEG Group, IJG&#xff09;开发&#xff0c;提供了功能强大的API&#xff0c;用于创建和读取JPEG文件。LibJPEG库支持JPEG的所有常见功能…

Cpp快速入门语法(上)(1)

文章目录 前言一、C关键字(C98)二、命名空间命名空间的定义命名空间的使用 三、C输入 & 输出四、缺省参数总结 前言 其实有时候我也会尝试代入下祖师爷本杰明当年在贝尔实验室的心理活动&#xff0c;我心想&#xff0c;他可能一开始是大抵受不了C语言的某些缺点&#xff0c…

梦想之家|AI技术赋能家居,重塑生活空间

人工智能&#xff08;AI&#xff09;在智能家居方面的应用非常广泛&#xff0c;极大地提升了家庭的便利性、安全性和能源效率。当前&#xff0c;AI技术的迅速发展&#xff0c;为传统家居产品带来了智能化升级。从智能单品到智能互联&#xff0c;AI技术的融入使得这些家居产品具…

DC-DC降压10A电源降压可调模块24V转12V9V5V3V-AH1514芯片

AH1514&#xff1a;一款高效率小体积的DC-DC降压电源芯片 摘要&#xff1a;本文介绍了一款高性能的DC-DC降压电源芯片——AH1514&#xff0c;该芯片具有24V转12V、9V、5V、3V可调输出&#xff0c;支持7V-38V输入&#xff0c;20A峰值输出电流&#xff0c;且具有小体积、高效率的…

C++速通LeetCode简单第19题-只出现一次的数字

方法一&#xff1a;暴力求解&#xff0c;排序后两个两个比较&#xff0c;两者不同时前者为答案&#xff1a; class Solution { public:int singleNumber(vector<int>& nums) {if(nums.size() 1) return nums[0];list<int> l;int ans 0;for(int i 0;i< n…

3.js - THREE.CubeTextureLoader() 添加环境纹理,以创建立方体贴图

使用 THREE.CubeTextureLoader() 添加环境纹理&#xff0c;以创建立方体贴图 不使用 THREE.CubeTextureLoader() 的时候 源码 import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls import { RGBELoader } from three/exam…

【话题讨论】AI时代程序员核心力:技术深耕,跨界学习,软硬兼备

目录 引言 一、AI辅助编程对程序员工作的影响 1.1 AI工具如何提升工作效率 1.2 AI工具的风险 1.3 应对策略 二、程序员应重点发展的核心能力 2.1 核心竞争力 2.2 企业和教育机构的调整 三、人机协作模式下的职业发展规划 3.1 持续学习的重要性 3.2 选择适合自己的…

电脑提示‘由于找不到 msvcr120.dll,无法继续执行代码’的科学解决方案分析

如果你在启动特定的应用程序或游戏时遇到错误提示&#xff1a;“由于找不到 msvcr120.dll&#xff0c;无法继续执行代码”&#xff0c;这表明你的系统可能缺少运行某些基于 Visual C 2013 开发的程序所需的关键组件。不过&#xff0c;不必担心&#xff0c;有几种方法可以解决这…

使用C++程序编写5 个浮点数,求平均值后输出

源代码如下&#xff1a; #include <iostream>using namespace std;int main() {float arr[5]{7,10,3,9,8};int i;float sum 0;float avg 0;for(i0;i<5;i){sum sum arr[i];}avg sum/5;cout << "平均值是&#xff1a;" << avg << endl…

VoIP协议

VoIP协议是VoIP业务的规范标准。我们都知道VoIP业务有着压倒性的优势。随着网络应用的多元化和低成本化发展&#xff0c;VoIP业务直接冲击着传统通信市场&#xff0c;那么目前VoIP协议目前常用的协议,如H.323、SIP、MEGACO和MGCP。 H.248 H.248是定义网关控制协议的ITU建议书…

squid代理及常见的代理上网(Squid Proxy and Common Proxy Internet Access)

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

【学术会议征稿】第九届计算机技术与机械电气工程国际学术论坛(ISCME 2024)

第九届计算机技术与机械电气工程国际学术论坛&#xff08;ISCME 2024&#xff09; 2024 9th International Seminar on Computer Technology, Mechanical and Electrical Engineering 第九届计算机技术与机械电气工程国际学术论坛&#xff08;ISCME 2024&#xff09;将于2024…