【并发编程】-- 自旋锁、读写锁

170 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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();
	 }
}