使用互斥锁和条件变量实现读写锁

只使用互斥锁和条件变量实现读写锁,此读写锁的实现优先考虑等待着的写入者。

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),刚开始学习网络编程,如有不正确之处请大家多多指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值