持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
自旋锁
信号量和互斥量都涉及任务的阻塞,一旦涉及到任务切换,就必将涉及内核层面的现场保存和恢复,这或许看来性能损耗较小,但是放大来看,这里面涉及到非常多的机制,包括了寄存器的状态保存、TLB的页刷新,页目录的切换等,简单而言,在内核层面任务的切换非常昂贵的。
自旋锁是锁的优化,也是一种锁,一般会结合其他带任务切换锁一起使用,因为一直让CPU执行无用代码也是损耗性能的表现,当CPU自选的损耗大于任务切换时间时,自旋锁就失去自身的意义了。
代码如下:
ConditionVariables conditionVariables;
Thread A{
for(::){
if(conditionVariables){
break;
}
}
}
Thread B{
for(::){
if(conditionVariables){
break;
}
}
}
注意点,这里沿用了条件变量,自旋锁现在都是和其他锁一起使用,如和条件变量等,也就是说,可将上述for循环变为for(int count=0;count<N;count++),这里的N就是次数,也就是让CPU一直执行任务的for循环,当到达N时
还没有获取锁而阻塞。
读写锁
查看一个场景,有N个读任务,即读取共享资源,但并不操作资源,还有M个任务写任务,需要读取共享资源,然后修改资源,修改完成后写回。
只要数据不涉及多个写任务,同时读取是不需要上锁的,因为没有线程安全问题,即便有N个读任务,但如果只有一个写任务,那么不需要上锁,只要保证写完后的共享资源能被读资源看到就行,这就是可见性。所有读操作不缓存,都是从内存中读取的,从而将复杂问题简单化。这个场景简化为"N读1写"的问题后,同一时间内只允许一个写线程操作资源,其他写任务必须等待,同时为了保证强一致性,不允许读线程在写线程写入时操作,即读写互斥、写写互斥、读读不互斥。
读写锁代码如下:
Thread ReaderA{
while(Condition){
wait();
}
}
Thread ReaderB{
while(Condition){
wait();
}
}
Thread Writer(){
while(Condition){
wait();
}
}