福建永安建设局网站,wordpress邮件有<>,wordpress 文章打不开,遵义市在哪里做网站文章目录1. 运行队列和运行状态2. 进程状态3. 两种特殊的进程僵尸进程孤儿进程4. 进程优先级5. 进程切换进程特性进程切换6. 环境变量的基本概念7. PATH环境变量8. 设置和获取环境变量9. 命令行参数1. 运行队列和运行状态
#x1f495; 运行队列#xff1a;
进程是如何在CP…
文章目录1. 运行队列和运行状态2. 进程状态3. 两种特殊的进程僵尸进程孤儿进程4. 进程优先级5. 进程切换进程特性进程切换6. 环境变量的基本概念7. PATH环境变量8. 设置和获取环境变量9. 命令行参数1. 运行队列和运行状态 运行队列
进程是如何在CPU上运行的CPU在内核上维护了一个运行队列进行进程的管理。让进程进入队列本质就是将该进程的task_struct 结构体对象放入运行队列之中。这个队列在内存中由操作系统自己维护。 运行状态 运行状态 进程PCB在运行队列里就是运行状态不是说这个进程正在运行才是运行状态。状态是进程内部的属性所有的属性在PCB里进程不只是占用CPU资源也有可能随时要外设资源。阻塞状态 进程因为等待某种条件就绪而导致的一种不推进的状态——进程卡住了此时的进程要通过等待的方式等待具体的资源被别人用完之后再被自己使用。阻塞状态进程的PCB被放在硬件的等待队列中。本质是对tack_struct对象放到不同的队列中 挂起状态 如果系统中存在许多进程进程短期内不会被调度代码和数据在短期内不会被执行此时如果内存空间不足操作系统就可以把代码和数据暂时保存到磁盘上节省一部分空间该进程暂时被挂起了这就是挂起状态。对于阻塞状态和挂起状态阻塞不一定挂起挂起一定是阻塞。 因此所谓的进程不同的状态本质是进程在不同的队列之中等待某种资源。 2. 进程状态
为了弄明白正在运行的进程是什么意思我们需要知道进程的不同状态。一个进程可以有几个状态在Linux内核里进程有时候也叫做任务。
下面的状态在kernel源代码里定义
/*
* The task state array is a strange bitmap of
* reasons to sleep. Thus running is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] {
R (running), /* 0 */
S (sleeping), /* 1 */
D (disk sleep), /* 2 */
T (stopped), /* 4 */
t (tracing stop), /* 8 */
X (dead), /* 16 */
Z (zombie), /* 32 */
};R运行状态running) : 并不意味着进程一定在运行中它表明进程要么是在运行中要么在运行队列里。S睡眠状态sleeping): 意味着进程在等待事件完成这里的睡眠有时候也叫做可中断睡眠interruptible sleep。D磁盘休眠状态Disk sleep有时候也叫不可中断睡眠状(uninterruptible sleep)在这个状态的进程通常会等待IO的结束。T停止状态stopped 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。X死亡状态dead这个状态只是一个返回状态你不会在任务列表里看到这个状态。Z僵尸状态zombie这个状态是一个已经运行完的子进程等待父进程回收他的返回值。 运行状态R 睡眠状态S 当我们执行可执行程序后在使用ps命令查看进程状态时发现他是S状态为什么我们的程序正在运行进程却是睡眠状态呢 这是因为我们使用printf进行打印时需要访问外设但外设的速度是远远低于CPU的所以进程大部分时间都在等待硬件资源的就绪所以我们每次查看时进程几乎都处于阻塞状态。 磁盘休眠状态D
当内存中的空间不足时操作系统会让一些进程进入挂起状态但是如果内存的空间严重不足时进程挂起也解决不了问题这个时候操作系统可能会将一些暂时挂起的进程或者没有被调度的进程杀掉。
但是如果要是此时挂起的进程正在向磁盘写入数据或者进行一些重要的数据传递时如果操作系统将这个进程杀死那么磁盘就可能会将正在传递的数据丢弃此时重要的数据就有可能因为操作系统将进程杀死导致重要数据的丢失。所以我们的深度睡眠状态就是针对这种情况而生的。深度睡眠状态下的进程既不能被用户杀死操作系统也无法将其杀死。只能通过断点或者等待进程自己醒过来。 暂停状态T
暂定状态也是阻塞状态的一种下面我们来看一下如何让一个运行状态下的进程暂停 我们可以使用kill的19号指令将一个进程从运行状态变为暂停状态。 如果想要使得休眠中的进程重新恢复运行状态只需要执行kill的18号命令即可 这里我们可以看到进程又重新进入了运行状态但是为什么进程重新进入云心状态后后面的 号 消失了呢
其实进程状态后面的 号 表示的是这个进程是一个前台进程如果没有 号就表示这个进程是一个后台进程。对于前台进程我们可以使用Ctrl c将其杀死但是对于后台进程我们只能使用kill命令杀死他。 追踪暂停状态t
属于暂停状态的一种表示进程正在被追踪。最典型的一种就是gdb调试进程的时候。 死亡状态X
表示一个进程结束运行他的PCB以及代码和数据全部都被操作系统回收。 僵尸状态Z
一个进程在退出的时候不能立即释放全部的资源但是该进程已经不会再被执行了该进程的PCB中存放着他的各种各样的状态码尤其是退出状态码。
僵尸状态就是为了在进程退出的时候能够让父进程或者操作系统拿到他退出状态码然后释放PCB的一种状态。 3. 两种特殊的进程
僵尸进程 僵死状态Zombies是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。僵死进程会以终止状态保持在进程表中并且会一直在等待父进程读取退出状态代码。所以只要子进程退出父进程还在运行但父进程没有读取子进程状态子进程进入Z状态。 下面我们来举例看一下僵尸进程 当我们杀掉子进程后由于父进程并没有读取子进程的退出状态码所以子进程进入了Z(僵尸状态)如果父进程一直不读取子进程的退出状态码那么子进程就会变成僵尸进程。 僵尸进程的危害 父进程如果一直不读取子进程的退出状态码那子进程就一直处于Z状态。维护退出状态本身就是要用数据维护也属于进程基本信息所以保存在task_struct(PCB)中。换句话说 Z状态一直不退出 PCB一直都要维护。那一个父进程创建了很多子进程就是不回收就会造成内存资源的浪费。 孤儿进程 父进程如果提前退出那么子进程就会被操作系统领养此时的子进程就称之为“孤儿进程”孤儿进程被1号init进程领养最后由init进程回收。 这里我们可以看到如果将父进程杀死后父进程并不会进入僵尸状态这是因为父进程在退出后会被父进程的父进程——bash所读取他的退出状态码。还有子进程被1号进程领养后会由前台进程变成后台进程。 4. 进程优先级 CPU的资源是有限的但是内存中有很多进程都需要占用资源所以需要给进程指定优先级来合理的分配资源。 CPU资源分配的先后顺序就是指进程的优先级priority。优先级高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用可以改善系统性能。还可以把进程运行到指定的CPU上这样一来把不重要的进程安排到某个CPU可以大大改善系统整体性能。 当我们输入ps -l/ps -al指令后就可以看到进程优先级相关的属性 UID : 代表执行者的身份PID : 代表这个进程的代号PPID 该进程的父进程的代号PRI 代表这个进程可被执行的优先级其值越小越早被执行NI 代表这个进程的nice值 下面我们重点介绍一下PRI和NI这两个变量PRIpriority 即进程的优先级或者通俗点说就是程序被CPU执行的先后顺序此值越小进程的优先级别越高。而NInice 表示进程可被执行的优先级的修正数值。需要强调一点的是进程的nice值不是进程的优先级他们不是一个概念但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据。
PRI值越小越快被执行那么加入NI值后将会使得PRI变为 PRI(new)PRI(old)NI这里我们需要注意的是每个进程默认的PRI都是80NI都是0但是NI的波动范围是[-2019]PRI与NI的和越小进程的优先级越高。
下面我们来看一下如何修改进程的优先级
(1) 输入top指令 (2) 输入r (3) 输入进程的id (4) 输入NI值 这里我们还需要注意的是普通用户无法直接修改NI的值必须切换成root用户或者使用sudo提权执行top指令。 5. 进程切换
进程特性 竞争性: 系统进程数目众多而CPU资源只有少量甚至1个所以进程之间是具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级独立性: 多进程运行需要独享各种资源多进程运行期间互不干扰并行: 多个进程在多个CPU下分别同时进行运行这称之为并行并发: 多个进程在一个CPU下采用进程切换的方式在一段时间之内让多个进程都得以推进称之为并发。 进程切换
一个CPU里面存在一套硬件寄存器宏观上寄存器分为用户可见用户不可见。
计算机调度某个进程时CPU会把这个进程的PCB地址加载到某个寄存器也就是说CPU内有寄存器可以只找到进程的PCB地址。
CPU里有一个eip寄存器PC指针指向当前执行指令的下一条指令的地址。
而进程运行的时候一定会产生很多的临时数据但这些临时数据只属于当前进程虽然CPU内部只有一套寄存器硬件但是寄存器保存的数据只属于当前进程也就是说寄存器硬件不是寄存器内的数据这是两码事寄存器被所有进程共享但是寄存器里的数据时每个进程各自私有的。
时间片引出——进程在运行的时候占有CPU但是却不是一直占有到进程结束进程都有自己的时间片因为时间片的存在进程会出现没有被执行完就被拿下去的情况这时候问题来了这个进程下一次如何在次回到CPU继续运行
进程切换的时候需要先进行上下文保护这里的上下文指的是CPU里的寄存器的数据而不是寄存器这里简单理解为临时数据保存至PCB里而当进程恢复运行的时候要进行上下文的恢复该进程在次回到CPU继续运行时重新加载恢复这些数据。 6. 环境变量的基本概念 环境变量(environment variables) 一般是指在操作系统中用来指定操作系统运行环境的一些参数。 如我们在编写C/C代码的时候在链接的时候从来不知道我们的所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途还有在系统当中通常具有全局特性。 当我们平常执行自己的可执行程序时必须在前面指定路径来执行但是执行Linux中的指令时并不需要指定路径这是什么原因呢 其实在Linux下的各种指令和我们平常自己编写代码生成的可执行程序没有什么区别他也是个可执行程序但是因为系统中存在PATH环境变量这些指令的地址都被存放在环境变量中当我们调用这些指令时系统会自定去PATH中寻找这些指令。 7. PATH环境变量 PATH是由一堆目录组成的各目录之间用冒号 “:” 隔开。 当执行某个 Linux 命令时Linux 会依照 PATH 环境变量中包含的目录依次搜寻该命令的可执行文件一旦找到即正常执行反之则提示无法找到该命令。 查看环境变量echo $PATH 添加PATH环境变量
(1) 直接添加 一般不建议使用这种方法添加因为我们写的程序没有经过测试容易污染指令池。
(2) 使用export命令添加 在这里我们还需要注意的是我们不能直接写成这样export PATH/home/Chenjiale/lesson2-22这样会导致把系统默认的环境变量PATH覆盖掉我们默认的那些指令就不能直接使用了只能通过指定路径的方式来使用。 系统中的其他环境变量 HOSTNAME 主机名USER 当前用户名PWD 当前系统路径HOME 当前用户的家目录HISTSIZE shell 能记忆的最多历史命令的条数 查看所有的环境变量env指令 下面我们来看一下环境变量是在系统中的哪个文件夹下面的 实际上当我们在登录 shell 时操作系统会让我们当前的 shell 进程执行 .bash_profile 中的内容而 .bash_profile 又会调用执行 .bashrc它们会将对应的环境变量导入到 shell 进程的上下文环境中。所以如果我们上面不小心将 $PATH 覆盖掉了也不用担心重新登录 shell 就好了。
环境变量是操作系统为了满足不同的应用场景预先在系统内设置的一大批全局变量这些变量往往具有特殊功能且能够一直被 bash 以及 bash 的子进程访问。环境变量具有全局属性的根本原因是环境变量会被子进程继承。 8. 设置和获取环境变量 设置和取消环境变量
如果我们直接在命令行中定义一个变量那么这个变量则是本地变量本地变量只在bash进程中有效。 当然我们可以使用export直接将本地变量设置为环境变量同时也可以直接使用export来定义一个环境变量。
export 已存在的环境变量 将本地变量设置为环境变量
export 新的变量 直接定义一个环境变量 如果我们不想要这个变量可以直接使用unset指令来取消变量当然我们也可以使用set指令来查看所有变量。 获取环境变量
获取环境变量除了可以使用echo $环境变量名之外还可以使用一个函数getenv()来获取。 下面我们举例来演示一下 在命令行上运行mytest时候bash就是一个系统进程mytest也会变成一个进程(通过fork创建父子进程)是bash的子进程。而环境变量具有全局属性的根本原因是会被子进程继承下去因为环境变量定义给bash而子进程会全部继承下去这就被称为环境变量。所以环境变量具有全局性而本地变量只会在当前进程bash内有效。
为了不同的应用场景让bash替我们寻找指令路径例如身份认证有些子进程需要用到这些信息确认当前用户的信息。
下面我们来举一个例子 这里我们一定要使用su -来验证我们可以使用getenv函数来获得当前的Linux用户判断其是否具有某种权限然后再执行对应的操作。 9. 命令行参数
我们知道在C语言中main函数也是有参数的不过我们平常一般都不需要手动传参而是被系统/父进行行传参的。所以这个参数可能会被大多数人忽略。
int main(int argc,char* argv[],char* env[])这里我们可以先来看一下前两个参数第一个参数是指第二个参数——指针数组中的元素个数。这里我们可以先来看一下指针数组中的每一个元素存的是什么。 其实这里的argv中的每一个元素都指向的是一个字符串argc用来指定数组中元素的个数他们配合可以使用-a -b -c 类似的选项功能。
下面我们来看一下最后一个指针数组中的内容 这里我们看到的是打印出来的就是环境变量的内容。这是因为env接收的就是父进程传递过来的环境变量的参数。
最后还有一种获取环境变量内容的方式就是通过环境变量表environ这里我们直接来验证一下即可。