了解多处理器情况下原子锁操作的问题
Understanding issues with atomic lock operations in case of multi processors
在单处理器的情况下,我们在执行锁定操作(锁定获取、锁定释放)之前禁用中断以防止上下文
切换,然后在操作之后我们重新启用它。
但是,在多处理器的情况下 CPU,仅禁用中断不足以使锁定操作原子化。
我从消息来源得知,
"It happens as each processor has a cache, and they can write to the same memory even with the interrupts being disabled."
Q1。为什么这在原子锁操作的情况下甚至很重要?
Q2。在仅禁用中断的多处理器环境中实现锁定操作时会出现哪些其他问题?
仅仅禁止中断是不够的,因为多处理器上的线程运行ning仍然可以同时访问同步对象函数内部的数据结构和代码,因此仅仅禁止中断是无法实现原子性的中断。
例如,假设 L 是一个 LOCK 对象,L.status 是 "FREE",而 X 是一个有四个线程 T1、T2、T3、T4 的进程,每个线程都是 运行ning 在不同的处理器 P1、P2、P3、P4 上。
让我们假设 LOCK::acquire() 的伪代码如下,
LOCK::acquire(){
if(status==BUSY){
lock.waitList.add(RunningThread);
TCB t == readyList.remove();
thread_switch(RunningThread,t);
t.state=running;
}
else{
status=BUSY;
}
}
如果我们只禁用中断,T1,T2,T3,T4的代码在相应的处理器上仍然可以运行。让我们假设锁在某一时刻是空闲的。
如果,所有线程同时尝试获取锁L,它们可能会同时检查锁的状态,在这种情况下,每个线程都会发现status=="FREE",每个线程都会获得锁,这将消除当前锁实现的适用性。
这就是为什么在为多处理器实现锁定对象时使用不同的原子操作,例如test_and_set。这些原子操作一次只允许来自一个多处理器的一个线程访问锁的代码。
在单处理器的情况下,我们在执行锁定操作(锁定获取、锁定释放)之前禁用中断以防止上下文 切换,然后在操作之后我们重新启用它。
但是,在多处理器的情况下 CPU,仅禁用中断不足以使锁定操作原子化。
我从消息来源得知, "It happens as each processor has a cache, and they can write to the same memory even with the interrupts being disabled."
Q1。为什么这在原子锁操作的情况下甚至很重要?
Q2。在仅禁用中断的多处理器环境中实现锁定操作时会出现哪些其他问题?
仅仅禁止中断是不够的,因为多处理器上的线程运行ning仍然可以同时访问同步对象函数内部的数据结构和代码,因此仅仅禁止中断是无法实现原子性的中断。
例如,假设 L 是一个 LOCK 对象,L.status 是 "FREE",而 X 是一个有四个线程 T1、T2、T3、T4 的进程,每个线程都是 运行ning 在不同的处理器 P1、P2、P3、P4 上。
让我们假设 LOCK::acquire() 的伪代码如下,
LOCK::acquire(){
if(status==BUSY){
lock.waitList.add(RunningThread);
TCB t == readyList.remove();
thread_switch(RunningThread,t);
t.state=running;
}
else{
status=BUSY;
}
}
如果我们只禁用中断,T1,T2,T3,T4的代码在相应的处理器上仍然可以运行。让我们假设锁在某一时刻是空闲的。
如果,所有线程同时尝试获取锁L,它们可能会同时检查锁的状态,在这种情况下,每个线程都会发现status=="FREE",每个线程都会获得锁,这将消除当前锁实现的适用性。
这就是为什么在为多处理器实现锁定对象时使用不同的原子操作,例如test_and_set。这些原子操作一次只允许来自一个多处理器的一个线程访问锁的代码。