8.1概述
只要没有线程在修改某个给定的数据,那么任意数目的线程都可以拥有该数据的读访问权。仅当没有其他线程在读或者修改某个给定的数据时,当前线程才能修改它
某些应用中,读数据比修改数据频繁,这些应用更加适用读写锁。这种对于某个给定资源的共享访问也称为共享-独占锁
8.2获取与释放读写锁
读写锁数据类型为pthread_rwlock_t.如果这个类型的变量是静态分配的,可通过给它赋常值PTHREAD_RWLOCK_INITIALIZER来初始化它
#include<pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwptr)
int pthread_rwlock_wrlock(pthread_rwlock *rwptr)
int pthread_rwlock_unlock(pthread_rwlock *rwptr)
下面两个函数尝试获取一个读出锁或写入锁,但是如果不能马上获得,那就返回一个EBUSY错误,而不是把调用线程投入睡眠
int pthread_rwlock_tryrdlock(pthread_rwlock *rwptr)
int pthread_rwlock_trywrlock(pthread_rwlock *rwptr)
8.3读写锁属性
读写锁变量可以通过pthread_rwlock_init来动态初始化,当一个线程不再需要某个读写锁时,可以调用pthread_rwlock_destory啊含糊摧毁它
int pthread_rwlock_init(pthread_rwlock_t *rwptr,const pthread_rwlockattr_t *attr)
int pthread_rwlock_destory(pthread_rwlock_t *rwptr)
初始化时,attr是个空指针,那么读写锁使用默认属性。如果要赋予它非默认属性,需要使用下面两个函数
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
int pthread_rwlockattr_destory(pthread_rwlockattr *attr)
当期定义了唯一的属性是PTHREAD_PROCESS_SHARED,它指定读写锁在不同进程间共享,二不仅仅是在单个进程内的不同线程共享,下面两个函数分别获取和设置这个属性
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr,int *valptr)
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int value)
8.4使用互斥锁和条件变量实现读写锁
只需要互斥锁和条件变量就可以实现读写锁,下面的实现优先考虑等待着的写入者。
typedef struct{
pthread_mutex_t rw_mutex;
pthread_cond_t rw_condreaders;
pthread_cond_t rw_condwriters;
int rw_magic;
int rw_nwaitreaders;
int rw_nwaitwriters;
int rw_refcount;
}pthread_rwlock_t;
int pthread_rwlock_rdlock(pthread_rwlock_t *rw)
{
int result;
if(rw->rw_magic!=RW_MAGIC)
return (EINVAL);
if((resulr=pthread_mutex_lock(&rw->rw_mutex))!=0)
return result;
while(rw->refcount<0||rw->nwaitwriters>0)
{
rw->rw_nreaders++;
result=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);
rw->rw_nreaders--;
if(result!=0)
break;
}
if(result==0)
rw->rw_recount++;
pthread_mutex_unlock(&rw->rw_mutex);
return (result);
}
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rw)
{
int result;
if(rw->rw_magic!=RW_MAGIC)
return(EINVAL);
if((result=pthread_mutex_lock(&rw->rw_mutex)!=0)
return(result);
if(rw->rwfcount<0||rw->nwaitwriters>0)
return EBUSY;
else
rw->rw_fcount++;
pthread_mutex_unlock(&rw->rw_mutex);
}
int pthread_rwlock_wrlock(pthread_rwlock_t *rw)
{
int result;
if(rw->rw_magic!=MAGIC)
return (EVIAL);
if((result=pthread_mutex_lock(&rw->rw_mutex))!=0)
return(result);
while(rw->rw_fcount!=0)
{
rw->rw_nwaitwriters++;
result=pthread_cond_wait(&rw->rw_condwriters);
rw->rw_nwaitwriters++;
if(result!=0)
break;
}
if(result==0)
rw->rw_fcount=-1;
pthread_mutex_unlock(&rw->rw_mutex);
return result;
}
int pthread_rwlock_unlock(pthread_rwlock_t *rw)
{
int result;
if(rw->rw_magic!=MAGIC)
return (EINVAL);
if((result=pthread_mutex_lock(&rw->rw_mutex)!=0)
return result;
if(rw->rw_fcount>0)
rw->rw_fcount--;
else if(rw->rw_fcount=-1)
rw->rw_fcount=0;
else
...........
if(rw->rw_nwaitwriters>0)
{
if(rw->rw_fcount=0)
result=pthread_cond_sigal(&rw->rw_condwriters);
}
else if(rw->rw_nwaitreaders>0)
result=pthread_cond_broadcast(&rw->rw_condreaders);
pthread_mutex_unlock(rw->rw_mutex);
return result;
}
8.5线程取消
如果pthread_rwlock_rdlock的调用线程阻塞在pthread_cond_wait调用上,随后被统一进程中的其他线程取消,它就在仍然持有互斥锁的情况下终止
我们可以在原有的代码中加入两行
rw->rw_nreaders++;
pthread_cleanup_push(rwlock_cancelrdwait,(void *arg))//添加清理处理程序
result=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);
pthread_cleanup_pop(0); //删除清理处理程序
rw->rw_nreaders--;
第一行代码建立一个清理处理程序,如果pthread_cond_wait返回,第二行新代码就要删除这个清理处理程序
下面看一下清理处理程序的代码
void rwlock_cancelrdwait(void *arg)
{
pthread_rwlock_t *rw;
rw=arg;
rw->rw_nwaitreaders--;
pthread_mutex_unlock(&rw->rw_mutex);
}
第一行代码建立一个清理处理程序,如果pthread_cond_wait返回,第二行新代码就要删除这个清理处理程序
下面看一下清理处理程序的代码
如果·pthread_rwlock_rdlock的调用线程在阻塞于该函数pthread_cond_wait期间被取消,它就不会从该函数返回,而是调用清理处理程序