注意:队列只是一格以前的称呼,底层是链表
多个cpu,每个cpu都有自己的进程队列
进程分类:
实时进程 与用户交互的进程,需要及时的响应(优先级 0~100)
普通进程 响应不需要那么及时的进程。压缩文件,视频的编码解码(由先级100~140)
上下文切换:
将p1进程的一些环境存放到内核的栈里面,然后将p2加载进内存中去运行
上下文:进程的一些信息,程序计数器,变量,程序运动到哪了,一些寄存器里面的值。保存在内核的栈里面
调度算法:
0~99 优先级 实时进程
轮询调度策略
将cpu分配给就绪队列首进程规定时间片时间,每个进程轮流的运行一个时间片,
时间片用完了就排到就绪队列的尾部 、同等优先级抢占,不同优先级时间片轮询
100~130 普通进程
完全公平的策略 cfs
按照优先级一个个运行,可以被实时进程抢占
每个进程的运行时间=sched_latency_ns * 进程权重值 / 运行队列上所有进程权重之和。
静态进程 可以在进程启动的时候使用nice 和sched_setscheduler()系统调用更改,否则的话运行期间保持恒定
linux进程状态
Linux系统中的进程主要有以下六种状态
(1)TASK_RUNNING(可运行状态)。正在运行的进程或在可运行进程队列(run_queue)中等待运行的进程处于该状态。它实际上包含一般操作系统原理教材中所谓进程三种基本状态中的运行态和就绪两种状态
个人认为 运行队列 与就绪队列 是彼此独立的
(2)TASK_INTERRUPTIBLE(可中断阻塞状态)。处于可中断阻塞状态的进程排成一个可中断阻塞状态进程队列,该队列中的阻塞进程在资源有效时,能被信号或中断唤醒进入到运行态队列
(3)TASK_UNINTERRUPTIBLE(不可中断阻塞状态)。不可中断指的是进程不响应信号。处于不可中断阻塞状态的进程排成一个不可中断阻塞状态进程队列。该队列中的阻塞进程,不可被其他进程唤醒,只有被使用wake_up()函数明确唤醒时才能转换到可运行的就绪状态
(4)TASK_STOP/TASK_TRACED(暂停状态)。当进程收到信号SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU时就会进入暂停状态。可向其发送SIGCONT信号,让进程转换到可运行状态
(5)TASK_DEAD-EXIT_ZOMBIE(僵死状态)。表示进程停止但尚未消亡的一种状态。此时进程已经结束运行并释放掉大部分资源,但父进程尚未收回其PCB。在进程退出时,将状态设为TASK_ZOMBIE,然后发送信号给父进程,由父进程再统计其中的一些数据后,释放它的task_struct结构。处于该状态的进程已经终止运行,但是父进程还没有询问其状态。
(6)TASK_DEAD-EXIT_DEAD(退出状态),处于此状态的进程即将被销毁,EXIT_ DEAD非常短暂,几乎不可能通过ps命令捕捉到。
不同的状态都有一个队列,存放着进程
挂起与阻塞之间的区别,挂起是将资源从内存中移除,是被动的,阻塞是资源不足仍在内存中
进程切换的内容
上下文切换:
将p1进程的一些环境存放到内核的栈里面,然后将p2加载进内存中去运行
上下文:进程的一些信息,程序计数器,变量,程序运动到哪了,一些寄存器里面的值。保存在内核的栈里面,
进程的创建
clone
写时复制:允许父子进程读取相同的物理页,单只有子进程准备写的时候才会去复制新的物理页
fork
轻量级进程允许父子进程共享很多内核数据结构:页表 打开文件表 信号处理等
vfork
vfork允许子进程共享父进程的内存地址空间
连接一个读进程一个写进程,以实现他们之间通信的共享文件。向管道提供输出的发送进程(即写进程),以字符流形式将大量的数据送入管道,而接收管道输出接收进程(即读进程)可以从管道中接收数据
管道的内部机制:
进程1 将自己的进程地址空间中的数据先复制到inode 指定的物理页面上,然后进程2 则复制 inode 指定的页面(同一个页面,即共享的数据页)上的数据到自己的进程地址空间上。这就完成了进程1的写,进程2的读,反之
一样。换句话说共享了一个物理页
多个进程都可以操作的队列,可以往里面写入数据和读取数据
不同进程之间本来同一个虚拟地址映射的物理地址是不同的,我们将它设置为相同的内存,这样就可以实现通信
信息理解为软件中断,每一个进程都维护者一个信号表,一个进程收到信号与处理器处理一个中断差不多
信号产生 -> 信号注册 -> 信号在进程中注销 -> 信号处理函数执行完毕
来自
内核对B进程信号设置完成后,就会发送中断请求给B进程,这样B进程就进入到内核态,这个时候进程B根据那个信号表,查找对应的此信号的处理函数,然后设置frame,设置好之后,跳回到用户态执行信号处理函数,处
理完成后,再次返回到内核态,再次设置frame,然后再次返回用户态,从中断位置开始继续执行
只能锁或者开锁
条件变量通常搭配互斥锁来
一个线程等待某个条件满足而被阻塞; 另一个线程中,条件满足时发出“信号
自旋锁
可以使用 pthread_spin_lock()函数或 pthread_spin_trylock()函数对自旋锁进行加锁,前者在未获取到锁时
一直“自旋”;对于后者,如果未能获取到锁,就立刻返回错误,错误码为 EBUSY。不管以何种方式加锁,
自旋锁都可以使用 pthread_spin_unlock()函数对自旋锁进行解锁。其函数原型如下所示注意:互斥锁在没获取到锁前访问会陷入睡眠
读写锁
当读写锁处于写加锁状态时,在这个锁被解锁之前,所有试图对这个锁进行加锁操作(不管是以读
模式加锁还是以写模式加锁)的线程都会被阻塞。
当读写锁处于读加锁状态时,所有试图以读模式对它进行加锁的线程都可以加锁成功;但是任何以
写模式对它进行加锁的线程都会被阻塞,直到所有持有读模式锁的线程释放它们的锁为止