只使用互斥锁和条件变量实现读写锁,此读写锁的实现优先考虑等待着的写入者。
1、pthread_rwlock_t数据类型
给出一个pthread_rwlock.h头文件,其中pthread_rwlock_t数据结构由一个互斥锁、一个读条件变量、一个写条件变量、一个标志位及三个计数量(读条件变量等候计数器、写条件变量等候计数器、读写锁引用计数器)构成。
/* include rwlockh */
#ifndef __pthread_rwlock_h
#define __pthread_rwlock_h
typedef struct {
pthread_mutex_t rw_mutex; /* basic lock on this struct */ //互斥锁
pthread_cond_t rw_condreaders; /* for reader threads waiting *///服务于读的条件变量
pthread_cond_t rw_condwriters; /* for writer threads waiting *///服务于写的条件变量
int rw_magic; /* for error checking *///读写锁初始化成功后,即被设置成RW_MAGIC,用来检测所传递的指针所指读写锁是否被初始化
int rw_nwaitreaders;/* the number waiting *///记录等待读出锁使用的数量
int rw_nwaitwriters;/* the number waiting *///记录等待写入锁使用的数量
int rw_refcount;//此值为-1表明写入锁正使用,为0,表明没有人使用读写锁,>1,表明有人使用读出锁
/* 4-1 if writer has the lock, else # readers holding the lock */
} pthread_rwlock_t;
#define RW_MAGIC 0x19283746
/* 4following must have same order as elements in struct above */
#define PTHREAD_RWLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, \
PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, \
RW_MAGIC, 0, 0, 0 }
typedef int pthread_rwlockattr_t; /* dummy; not supported */
/* 4function prototypes */
int pthread_rwlock_destroy(pthread_rwlock_t *);
int pthread_rwlock_init(pthread_rwlock_t *, pthread_rwlockattr_t *);
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *);
int pthread_rwlock_unlock(pthread_rwlock_t *);
int pthread_rwlock_wrlock(pthread_rwlock_t *);
#endif __pthread_rwlock_h
/* end rwlockh */
2、pthread_rwlock_init函数
pthread_rwlock_init动态初始化一个读写锁。
/* include init */
#include "unpipc.h"
#include "pthread_rwlock.h"
int
pthread_rwlock_init(pthread_rwlock_t *rw, pthread_rwlockattr_t *attr)
{
int result;
if (attr != NULL)
return(EINVAL); /* not supported */
if ( (result = pthread_mutex_init(&rw->rw_mutex, NULL)) != 0)//最后一个NULL,表示不给rwlock互斥锁赋属性,下同
goto err1;
if ( (result = pthread_cond_init(&rw->rw_condreaders, NULL)) != 0)
goto err2;
if ( (result = pthread_cond_init(&rw->rw_condwriters, NULL)) != 0)
goto err3;
rw->rw_nwaitreaders = 0;
rw->rw_nwaitwriters = 0;
rw->rw_refcount = 0;
rw->rw_magic = RW_MAGIC;
return(0);
err3:
pthread_cond_destroy(&rw->rw_condreaders);
err2:
pthread_mutex_destroy(&rw->rw_mutex);
err1:
return(result); /* an errno value */
}
/* end init */
3、pthread_rwlock_destroy函数
/* include destroy */
#include "unpipc.h"
#include "pthread_rwlock.h"
int
pthread_rwlock_destroy(pthread_rwlock_t *rw)
{
if (rw->rw_magic != RW_MAGIC)//通过此标志位检测是否已初始化该读写锁
return(EINVAL);
if (rw->rw_refcount != 0 ||//此条件语句检测读写是否不在使用中
rw->rw_nwaitreaders != 0 || rw->rw_nwaitwriters != 0)
return(EBUSY);
pthread_mutex_destroy(&rw->rw_mutex);
pthread_cond_destroy(&rw->rw_condreaders);
pthread_cond_destroy(&rw->rw_condwriters);
rw->rw_magic = 0;//此标志位置0,表明此读写锁不再使用
return(0);
}
/* end destroy */
4、pthread_rwlock_rdlock函数
/* include rdlock */
#include "unpipc.h"
#include "pthread_rwlock.h"
int
pthread_rwlock_rdlock(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);
/* 4give preference to waiting writers */
while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) {//正在有写入锁或有等待需要调用写入锁时,条件为真
rw->rw_nwaitreaders++;//给需要调用读取锁者数量+1
result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);//进入睡眠,释放互斥锁,等待读条件变量信号刺激
rw->rw_nwaitreaders--;//一旦被读条件变量信号刺激,说明可以进行加读出锁,给需要调用读取锁者数量-1
if (result != 0)
break;
}
if (result == 0)
rw->rw_refcount++; /* another reader has a read lock */
pthread_mutex_unlock(&rw->rw_mutex);//加读取锁完成,释放互斥锁
return (result);
}
/* end rdlock */
稍后将看到,当给一个读写锁解锁时,首先检查是否有任何等待着的写入者(体现了优先考虑写入者原则),若没有则检查是否有任何等待着的读出者。如果有读出者在等待,则向rw_condreaders条件变量广播信号。
5、pthread_rwlock_tryrdlock函数(无法上读取锁,即返回EBUSY错误,实现比较简单)
/* include tryrdlock */
#include "unpipc.h"
#include "pthread_rwlock.h"
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->rw_refcount < 0 || rw->rw_nwaitwriters > 0)
result = EBUSY; /* held by a writer or waiting writers */
else
rw->rw_refcount++; /* increment count of reader locks */
pthread_mutex_unlock(&rw->rw_mutex);
return(result);
}
/* end tryrdlock */
6、pthread_rwlock_wrlock函数
/* include wrlock */
#include "unpipc.h"
#include "pthread_rwlock.h"
int
pthread_rwlock_wrlock(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);
while (rw->rw_refcount != 0) {//条件为真,表明有调用者持有写入锁或读出锁,这时不能直接上写入锁
rw->rw_nwaitwriters++;//调用写入锁者的数量+1
result = pthread_cond_wait(&rw->rw_condwriters, &rw->rw_mutex);//投入睡眠,释放互斥锁,等待着写条件变量信号刺激
rw->rw_nwaitwriters--;//一旦被写条件变量信号刺激,说明可以进行加写入锁,给需要调用写入锁者数量-1
if (result != 0)
break;
}
if (result == 0)
rw->rw_refcount = -1;
pthread_mutex_unlock(&rw->rw_mutex);//释放互斥锁
return(result);
}
/* end wrlock */
稍后将看到,向写条件变量发信号的前提是:它所在的读写锁被释放,并且有写入者正在等待。
7、pthread_rwlock_trywrlock函数(无法上写入锁,即返回EBUSY错误,实现比较简单)
/* include trywrlock */
#include "unpipc.h"
#include "pthread_rwlock.h"
int
pthread_rwlock_trywrlock(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->rw_refcount != 0)
result = EBUSY; /* held by either writer or reader(s) */
else
rw->rw_refcount = -1; /* available, indicate a writer has it */
pthread_mutex_unlock(&rw->rw_mutex);
return(result);
}
/* end trywrlock */
8、pthread_rwlock_unlock函数
/* include unlock */
#include "unpipc.h"
#include "pthread_rwlock.h"
int
pthread_rwlock_unlock(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->rw_refcount > 0)
rw->rw_refcount--; /* releasing a reader */
else if (rw->rw_refcount == -1)
rw->rw_refcount = 0; /* releasing a reader */
else
err_dump("rw_refcount = %d", rw->rw_refcount);
/* 4give preference to waiting writers over waiting readers */
if (rw->rw_nwaitwriters > 0) {//优先考虑获取写入锁的等待者
if (rw->rw_refcount == 0)//表明读写锁被释放,且有需要等待获取写入锁的调用者时,给予写条件变量信号刺激
result = pthread_cond_signal(&rw->rw_condwriters);
} else if (rw->rw_nwaitreaders > 0)//当有需要读出锁时
result = pthread_cond_broadcast(&rw->rw_condreaders);//广播读条件变量信号
pthread_mutex_unlock(&rw->rw_mutex);
return(result);
}
/* end unlock */
以上知识点来均来自steven先生所著UNP卷二(version2),刚开始学习网络编程,如有不正确之处请大家多多指正。