要实现读写锁,首先要知道读写锁的特性,除了“读者可并发,写者要排它”之外还要考虑避免写者饥饿的问题。综合考虑后可以讲读写锁的实现总结为一下四点:
1.当已经被施加写锁的时候,读锁写锁都不能在施加(写锁只能锁一次)
2.当已经被施加读锁时,还可以继续施加读锁,但不能施加写锁
3.有等待的写者时不能在获取读锁(保证写者优先)
4.解锁时有如果写者在等待,不能唤醒读者。
我们使用互斥量(mutex)和条件变量来实现读写锁,这也是大多数系统的实现方式。另外本文主要想说明的是读写锁的实现思路,所以这里只实现最基本的三个操作:申请读锁、申请写锁、解锁。而不实现初始化、trylock、销毁锁等操作。
点击(此处)折叠或打开
-
typedef struct
-
{
-
pthread_mutex_t rw_mutex; //对整个结构体提供互斥访问
-
pthread_cond_t rw_condreaders;//用于通知申请读锁的线程
-
pthread_cond_t rw_condwriters;//用于通知申请写锁的线程
-
int rw_waitreaders; //等待申请读锁的线程数
-
int rw_waitwriters; //等待申请写锁的线程数
-
int rw_refcount; //表示读写锁的状态,如果是-1表示它是一个写锁
-
}pthread_rwlock_t; //0表示它是可用的,大于0表示当前容纳的读锁数量
-
-
-
int pthread_rwlock_rdlock(pthread_rwlock_t *rw) //申请读锁
-
{
-
int result; //返回值(出错状态)
-
-
pthread_mutex_lock(&rw->rw_mutex);
-
//当写锁正在使用时不能上读锁,当锁可用但有线程等待申请写锁时一样也不能上读锁,这一点体现出来“写者优先”
-
while(rw->rw_refcount<0||rw->rw_waitwriters>0)
-
{
-
rw->rw_waitreaders++;
-
result=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);//等待读条件就绪
-
rw->rw_waitreaders--;
-
if(result!=0)
-
break;
-
}
-
if(result==0)
-
rw->rw_refcount++; //又有一个新的线程获取了读锁
-
-
pthread_mutex_unlock(&rw->rw_mutex);
-
return (result);
-
}
-
-
-
int pthread_rwlock_wrlock(pthread_rwlock_t *rw) //申请写锁
-
{
-
int result; //返回值(出错状态)
-
-
pthread_mutex_lock(&rw->rw_mutex);
-
//这里只检查锁是否可用
-
while(rw->rw_refcount!=0)
-
{
-
rw->rw_waitwriters++;
-
result=pthread_cond_wait(&rw->rw_condwriters,&rw->rw_mutex);//等待写条件就绪
-
rw->rw_waitwriters--;
-
if(result!=0)
-
break;
-
}
-
if(result==0)
-
rw->rw_refcount=-1; //线程获取了写锁
-
-
pthread_mutex_unlock(&rw->rw_mutex);
-
return (result);
-
}
-
-
-
-
-
int pthread_rwlock_unlock(pthread_rwlock_t *rw)//释放锁(读锁、写锁)
-
{
-
int result;
-
-
-
pthread_mutex_lock(&rw->rw_mutex);
-
if(rw->refcount>0)
-
rw->refcount--;
-
else if(rw->refcount==-1)
-
rw->refcount=0;
-
else
-
printf("rw->refcount=%d\n",rw->refcount);
-
//先看是否有写者在等待,如果有的话先唤醒写者,这是“写者优先”的另一体现
-
if(rw->rw_waitwriters>0)
-
{//不能写成if(rw->rw_waitwriters>0&&rw->refcount==0)
-
if(rw->refcount==0)
-
result=pthread_cond_signal(&rw->rw_condwriters);
-
}
-
else if(rw->rw_waitreaders>0)
-
result=pthread_cond_signal(&rw->rw_condreaders);
-
-
-
pthread_mutex_unlock(rw->rw_mutex);
-
return result;
-
}
不能写成if(rw->rw_waitwriters>0&&rw->refcount==0)的原因是:
这样会造成写者"饥饿",也就是应当保证,当有写者在等待申请锁的时候,不能在让读者来申请锁,否则由于读者可以多次加锁,一个持续的读请求流可能永远阻塞某个等待的写者。写成if(rw->rw_waitwriters>0&&rw->refcount==0),当第一个条件满足而第二个条件不满足,也就是有写者在等待,而还有读者在使用锁的情况,我们应该仅仅释放一个读锁,别的什么也不做,而这里却会执行else if,导致唤醒等待的读者,使读者获取到锁。
阅读(1061) | 评论(0) | 转发(0) |