1.调整进程的优先级
1.tast_struct中有很多字段,优先级只是其中的某种字段,比如int prio,就可以用一个整数或是若干个整数来表示进程的优先级。Linux中优先级数字越小,优先级越高。优先级决定进程获取资源的顺序。
2.cpu资源是较少的,进程是较多的,所以要有优先级。
操作系统调度和优先级的原则:我们现在接触的大部分操作系统是分时操作系统,简单理解就是cpu基于时间片对进程调度的。操作系统要保证调度进程时做到基本的公平,如果破坏优先级规则,进程长时间得不到cpu资源,就会造成进程的饥饿问题。
3.进程优先级的查看方式:ps-al,a表示all,l表示list。
PRI:进程优先级。NI:nice值。表示进程优先级的修正数据。
新的优先级=优先级+nice。
nice/renice(查)
可以用nice/renice调整优先级,也可以用top命令调整优先级。调整时,不可以用小键盘。
调整完成后,可以用ps -al查看对应进程的优先级。(在进程运行时调整)。
nice值不可以任意调整,范围【-20,19】一共40个数字。
如果在修改nice值时,输入很大的数,比如100,系统只会取nice值的上限就是19,然后和原来的优先级相加。并且普通用户不可以频繁的更改进程的优先级(只能改一次),而超级用户可以多次更改。
在进程控制块中,控制优先级主要有三个字段:1.prio 2.default prio(默认是80) 3.nice
nice和default prio相加得到prio。由此可知,每次调整优先级时,都是在default prio(80)的基础上更改的。
操作系统会对进程的优先级处理的比较好,用户也不太了解操作系统,所以尽量不要调整进程的优先级,除非是特殊的应用场景!
上面的图片对这些概念介绍得比较清楚,补充一点:
如果一台电脑有多个cpu,那么一定是并行和并发同时存在。所谓能力越大,责任就越大,既然用户得电脑配置高,用户一定会给电脑安排与之配置相对等得任务,所以,进程永远是多数,cpu永远是少数,在并行的同时就会存在并发。
2.命令行参数
上图中的./myprocess -a -b -c -d这个东西叫命令行字符串,argv显然是变长数组,argc是一个整型,命令行字符串以空格分隔,argc代表其中字符串的个数,argv里面存了对应的字符指针,最终以NULL结尾。系统将命令行字符串中的空格替换成'\0',这样就把这一个字符串分成了多个字符串,然后存在argv中。
这个程序可以验证argv最后一个指针是NULL,因为以argv[i]作为循环的判断条件,最终循环能够停下来,说明argv最后一个指针是NULL。为0,退出循环。
那么为什么要有命令行参数呢?
命令行参数的用途:
实现同一个程序的不同功能!
因此Linux中的命令的各种选项就可以解释了!
那么是谁处理命令行字符串,传递给argc和argv的呢?
命令行中启动的进程其实都是bash的子进程,这里bash的pid:10069
bash:命令行解释器。命令行字符串默认传递给bash,bash会对命令行字符串做解释,定义出一个字符指针数组argv和一个整型argc,然后再将它们传递给子进程的main函数。
bash会拿到命令行字符串,初始化main函数中的参数,然后再交给子进程。因为父进程中的数据默认能被子进程看到并访问!
总结:Linux中大多数指令都是用C语言写的,其中的-a -l等选项都是与命令行参数相关。
用户执行一个系统指令与执行用户写的一个程序没有任何区别!
3.环境变量
问题:为什么执行系统指令的时候可以不用带路径,而执行用户写的程序时一定要带路径呢?(./a.out&ls)。
因为Linux中存在一些全局的设置,告诉命令行解释器,应该去那些路径寻找可执行程序。
其中一些设置叫做环境变量,环境变量中有一个叫PATH。
想获得它的内容需要执行:echo $PATH。$相当于读取的意思。
系统中有很多的配置,在我们登录Linux系统的时候,其中一些配置以及被加载到bash进程中(内存)。
bash在执行命令时,通过环境变量找到命令并且加载。环境变量中的路径就是bash在执行命令时默认的搜索路径,这些路径以:作为分割符,逐一查找,如果没有找到,就会给用户提示没有找到:
。如果找到了就直接加载,运行对应的程序:
所以在用户执行系统指令的时候不需要加路径!
自己写的程序可不可以像指令一样不用加路径呢?
可以!
方法一:将用户写出的程序拷贝到系统路径下。(这个过程相当于在Linux系统中按装程序)
这个操作需要指令提权,普通用户不可以!
但是不建议把自己写的可执行程序安装到系统路径里面,会污染系统指令级程序。
这个过程相当于将可执行程序从Linux系统中卸载下来。
方法二:修改环境变量。
但是这样改环境变量的话,系统的很多命令都跑不了了。
PATH只是环境变量中的其中一个,是内存级的(在系统的配置文件里有!),如果不小心修改了这个环境变量,不用担心,只需关掉Xshell再重新打开就可以了!
正确的修改方式应该如下:
但这种做法不是永久有效的,下次打开Xshell的时候又变回去了!
方法三:修改环境变量的配置文件。
环境变量不是在内存中,而是在系统的配置文件中。在用户登录Linux系统时,bash进程会读取配置文件,将配置文件中的环境变量在bash进程中拷贝一份。所以要想永久的修改环境变量,需要修改系统的配置文件!
配置文件在哪里呢?
前两个在用户的家目录中(包括root和普通用户),可用ls -al查看。
第三个是在根目录下,etc目录中的bashrc文件。
这些配置文件会被bash进程读取导入到内存中。
将自己可执行程序的路径加到PATH中就完成了!从此以后,执行/home/user_111路径下的可执行程序再也不用加路径了!
3.1windows中的环境变量
当然,windows中也有环境变量!
env:查看环境变量。
3.2其他环境变量
HOME:记录用户的家目录。
PWD:记录当前所在路径。
SHELL:在系统启动的时候,就会将该路径的程序运行起来,所以就有了命令行解释器。
、
HISTSIZE:Linux系统记录最新的1000条历史命令,便于搜索。
可以使用history查看历史命令!
HOSTNAME:记录主机名。
USER:用户名。
查看所有的环境变量:env
查看单个环境变量:echo $XXX。
自己定义一个环境变量:
export:导入环境变量。
unset:取消环境变量。
像这种没有加export,env查不到,就不是环境变量,但是可以查到它的内容,这叫本地变量。
以后会讲到本地变量,这里还不着急。
4.代码获得环境变量
通过代码也可以获得环境变量,效果与env相同,说明子进程可以拿到环境变量,环境变量默认在bash内部。
也可以通过参数列表访问环境变量。
还可以通过getenv来访问环境变量的内容。
获得环境变量的方式:
方法一:通过extern char** environ;获取。
方法二:通过命令行参数char* env[]获取。
方法三:通过getenv获取。
虽然有三种方式,但本质上都是在bash中的环境变量表中查找的!
4.1bash如何组织环境变量
bash在启动时,会维护两张表:
第一张:char* env[],从配置文件中获得环境变量的地址,加载到该表中,bash内部就有环境变量了。该表的最后一个元素一定是NULL,这与char* argv[]类似。
上图中的char* environ就是指向的char* env[]。
结论:bash进程启动时会维护两张表:1.命令行参数表char* argv[]。2.环境变量表char* env[]。bash通过各种方式传给子进程。前置通过用户输入的命令行得到,后者在OS的配置文件中得到。
其实echo $PATH,PATH中的内容就是从环境变量表中得到的。
搞清楚了环境变量与环境变量表的关系后,我们可以验证,用export导入环境变量后,也可以用我们在上文写的代码拿到这些环境变量!
说明环境变量具有系统级的全局性,因为环境变量本身会被子进程继承下去。
这句话的意思就是,bash创建的子进程,它可以继续创建子进程,子进程依然可以创建子进程。不管创建多少个子进程,这些进程都可以拿到bash中的环境变量,因此,我们说:环境变量具有系统级的全局属性。
4.1.1普通命令与内建命令
有一个问题:export是指令,bash执行时会创建子进程,子进程里修改的数据父进程是看不到的,但是执行完export命令后父进程可以看到!这时为什么呢?
指令分为普通命令和内建命令,其中,内建命令是由bash亲自执行!
理解bash亲自执行:
bash是用c语言写的,c语言中有很多函数调用,而在bash内部就有一些函数调用,比如:
void export();void echo();等。当系统检测到用户执行对应命令时,bash不会创建子进程,bash自己执行这些命令!
验证有内建命令的存在:
把PATH清空后,export和echo依然正常!说明bash自己就可以搞定,不需要找系统路径去创建子进程!
4.1.2本地变量与环境变量
上图中的HELLO只是在内存中,但没有添加到环境变量表中,通过查看环境变量的方法查不到,这种变量叫做本地变量。
本地变量与环境变量的区别如下:
unset可以释放环境变量。
上图说明echo是内建命令,因为子进程无法继承本地变量,若是子进程,则无法获得本地变量的内容!