自旋锁/读者写者问题

自旋锁

自旋锁的概念和理解

锁在处理需要申请加锁的线程的时候,一般有两种处理方法:一种是挂起等待,另外一种是自旋。自旋即轮询。

挂起等待:

当一个线程成功申请锁,并进入临界区后,其它线程在申请的时候会被挂起等待,即处于阻塞状态。

自旋锁:

当一个线程成功申请锁,并进入临界区后,其它线程在申请的时候会不断地来查看这个线程是否释放了锁,即不断轮询,如果释放了,就会竞争锁。

那么是什么决定了使用哪种处理方式呢?

决定于在临界区中的线程要在临界区呆多长时间。但是是没有定义时间长短的。

一般来说,我们都采用挂起等待的方式,而不会采用自旋,因为自旋会很消耗CPU资源,挂起等待不会占用CPU资源。除非我们能够确定当前情况非常适合自旋。

自旋锁的接口介绍:

加锁:

 解锁:

 自旋锁的初始化:

我们能够发现,自旋锁跟我们使用一般的锁的接口很像,比如

自旋锁/读者写者问题_第1张图片

读者写者问题

读写锁概念

在多线程的场景下,有一种情况很常见,那就是公共数据很少会去被修改,即很多情况都是只读,然后很少写。如果在这种大多只读的情况下, 我们还要对线程进行加锁解锁等等,会有很多不必要的消耗。因此,读写锁就能够专门处理这种少写多读的情况。

读者写者跟生产消费者模型很像,其中,写者与读者的关系为互斥与 同步,写者与写者的关系为互斥,而读者与读者之间没有互斥和同步的关系。因为读者写者模型,读者不会拿走临界区的资源,因此也就没有读者与读者之间的互斥关系。

读写锁适合的场景是一次写入,大部分时间都在只读并且不做修改。

读写锁的接口了解:

初始化

自旋锁/读者写者问题_第2张图片

写者的加锁

自旋锁/读者写者问题_第3张图片

 读者的加锁

 解锁

这里我们可以观察到,锁的接口的使用方法很多都是一样的,因此学习成本也比较低,只要学会了mutex锁的接口使用方法就OK了。

读写锁的原理

接下来通过伪代码来了解一下读写锁的工作原理。

读者优先

当读者和写者竞争时,读者优先,当读者的数量大于0,那么就把写者的锁拿走,不让写者进入临界区。当读者的数量为0,那么写者申请锁,可以进入。

读者的加锁:

添加锁:
    pthread_mutex_t rdlock;//锁的变量
    int reader_count = 0;//初始化,用于计数,读者的数量

	lock(&rdlock);//为读者加锁,保证线程安全
	reader_count++;//读者的数量加一
	if(reader_count==1) lock(&wrlock);//如果读者的数量为1,把写者的锁拿走,不让写者进来写了
	unlock(&rdlock);//读者解锁

	//读取数据
    //......

	lock(&rdlock);//加锁,保证线程安全
	reader_count--;
	if(reader_count==0) unlock(&wrlock);//当读者的数量为0,把写者的锁还回去
	unlock(&rdlock);

写者的加锁:

pthread_mutex_t wrlock;
lock(&rwlock);
//写入数据
//.....
unlock(&wrlock);

写者优先

写者优先很少用到。所谓的写者优先,是在临界区中读者的数量大于0,后面还有读者想要申请进入临界区,此时写者就会比他们优先。

你可能感兴趣的:(Linux,操作系统,开发语言,c++)