序言
1.OS以进程、线程的方式在CPU中执行静态保存在外存(内存)中的程序,进程的构成与状态转化,特别是进程的切换;
2.当有多个进程处于就绪态,有哪些常见的挑选以执行方式;
3.并发执行(乱序发射)的进程,共享内存等资源,很可能修改其他程序的变量,需作同步处理来控制;
此外有些资源如打印机不能共享,需作互斥处理;
因为在大多数操作系统中,内核是单线程运行的,所以当一个线程被阻塞时,它会释放CPU资源。这将导致其他线程在等待CPU资源时也被阻塞,其他线程只能要么等待,无法保存现场(工作在用户层)再切换,produce block。
在内核级线程中,中断的保存/恢复现场为内核的功能,可以实现线程间的调度,且支持多处理机。
在组合方式中,
a. 用户进程的多个线程对应内核级的多个线程,用户1个线程系统调用的内核级线程A被阻塞,CPU可以切换到其他线程的不同内核级线程B;
b. 多核处理器可对应多个内核级线程;
同步与互斥都围绕共享资源的使用:
1.对于那些只能被单独访问的共享资源,要做互斥处理;
2.对于那些可以被共享访问的资源,虽然RAR没问题,但RAW,WAR,WAW 均可能导致最终的共享资源结果不同,要作同步处理。
互斥可通过用户程序中使用API实现lock和release
双标志互斥alg的问题是进程的线程乱序执行导致的,只有Peterson alg能在所有乱序执行保证同步的3大准则:
空则让进,忙则等待,有限等待,(让权等待)。
硬件实现有中断屏蔽和硬件指令2种方法:
boolean TestandSet(boolean *lock){
boolean old;
old=*lock;
*lock=true;
return old;;
}
while TestandSet(&lock);
临界区
lock=false;
剩余区
comment:
Swap(boolean *a,boolean *b){
boolean temp;
temp=*a;
*a=*b;
*b=temp;
}
key=true;
while(key!=false)
swap(&key,&lock);
临界区
lock=false
剩余代码
comment:
实现临界区互斥的硬件方法和软件方法各有什么优势?
硬件方法的优势:
原子性操作:硬件方法通常使用特定的指令或硬件机制来实现原子操作,如原子交换(Atomic Exchange)或测试并设置(Test-and-Set)。这些操作在硬件级别上保证了操作的原子性(不会出现共用临界资源),无需额外的软件开销。
性能:硬件方法通常比软件方法更高效,因为它们直接利用了硬件的特性,如高速缓存和并行处理能力。这使得硬件方法更适合于对性能要求较高的应用场景。
软件方法的优势:
可移植性:软件方法不依赖于特定的硬件指令或机制,因此更易于在不同的平台上实现和移植。这使得软件方法更具通用性,可以应用于不同类型的系统和架构。
灵活性:软件方法通常可以更灵活地实现复杂的同步机制,如信号量、条件变量等。这些机制提供了更多的控制和功能,可以满足不同线程同步需求。
容错性:软件方法可以在一些特殊情况下提供更好的容错性。例如,当硬件出现故障或不支持某些原子操作时,软件方法可以通过算法和复杂的同步机制来弥补。
需要注意的是,硬件方法和软件方法并不是互斥的选择,它们可以结合使用来提供更可靠和高效的同步机制。例如,硬件指令可以用于实现基本的原子操作,而软件方法可以用于构建更复杂的同步机制。选择何种方法取决于具体的应用需求、平台特性和性能要求。
acquire(){
//锁被占用则等待
while(available!=true)
;
//锁空闲,占用后,将锁设为false
available=false;
}
release(){ //释放锁
available=true;
}
采用两个不可中断(软件中由屏蔽中断方法实现)的原语——wait和signal来管理
wait(S){ //请求资源
while(S<=0) ; //若没有资源,则等待
S--; //占用资源,S--
}
signal(S){
S++; //释放资源
}
Defect:wait在无资源可用,会一直occupy cpu——while query,违背 让权等待
typedef struct{
int value;
struct process *L;
} semaphore(信号量);
请求资源
void wait(semaphore S){
S.value--; //S>0则资源数--;S<0则阻塞进程数++;
if(S.value<0){
add this process to S.L;
block(S.L);
}
}
释放资源
voic signal(semaphore S){
S.value++; //资源数++或阻塞进程数--
if(S.value<0){ //若为后者,唤醒该进程——资源来临
remove process P from S.L;
wakeup(P);
}
}
只有互斥用到了临界资源;
同步和前驱只关于特定变量的逻辑序;
同步
——进程按照(资源的)特定顺序执行
semaphore S=0;
P1(){
x;
V(S);
...
}
P2(){
...
P(S);
y;
...
}
互斥——只有1个进程能进入临界区
semaphore S=1;
P1(){
...
P(S);
critical area;
V(S);
}
P2(){
...
P(S);
critical area;
V(S);
}
用同步实现前驱关系——每个偏序关系用1个资源
S1(){
V(a1);
}
S2(){
P(a1);
V(b1);V(b2);
}
分析同步、互斥、前驱关系,设置信号量,确定P,V
背景:针对每个共享变量,所有使用变量都要设置P(),V()操作;
改进:每个共享资源,只要1个共享数据结构demo来管理;
管程=类,成员变量为共享资源的数目,成员函数为对共享资源的操作,如对互斥变量的take_away和release,
多个共享资源可以用记录型信号量表示,
不知道为什么要把条件变量单独拎出来,用来表示进程被阻塞的原因,
安全状态:按照某种推进顺序,能满足每个进程对资源的最大需求,使每个进程可顺序完成;
死锁避免在分配资源给进程的过程中拒绝进入dangerous state
banker’s alg一般都是DFS+回溯,可以用BFS?
破圈法是为了寻找有环图的最小生成树,
死锁检测定理——待证
1)找出非阻塞(请求的资源数量均不大于系统的空闲资源数量)的非孤立进程Pi,释放Pi所有资源;
2)重复1),若消去所有边,图可完全简化 ↔ \leftrightarrow ↔ 不死锁;