一:概述
- 使用场景
对数据结构读的次数远大于写的情况。
- 状态
(1)读模式下加锁状态 (读锁)
(2) 写模式下加锁状态 (写锁)
(3) 不加锁状态
- 遵循规则
(1)读写锁是"写模式加锁"时, 解锁前,所有对该锁加锁的线程都会被阻塞。
(2)读写锁是"读模式加锁"时, 如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞。
(3)读写锁是没有读者,也没有写者,那么写者可以立刻获得读写锁,如果读写锁没有写者,那么读者可以立即获得该读写锁。
(4)读锁、写锁并行阻塞,写锁优先级高,也叫共享-独占锁:写独占、读共享。
二:详细函数说明
- 读写锁声明
pthread_rwlock_t rwlock;
- 初始化一个读写锁,相同的一个锁对象不能初始化两次
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
参数说明:
rwlock —— 创建的读写锁
attr —— 读写锁属性,NULL代表读写锁的各种属性取默认值。
返回值:初始化成功返回0;否则返回错误编号。
- 销毁一个读写锁
int pthread_rwlock_destroy( pthread_ rwlock_t * rwlock );
参数说明:
rwlock —— 需要销毁的的读写锁
返回值:销毁成功返回0;否则返回错误编号。
- 加锁
int pthread_rwlock_rdlock ( pthread_ rwlock_t * rwlock);//读模式加锁
int pthread_rwlock_wrlock ( pthread_ rwlock_t * rwlock);//写模式加锁
参数说明:
rwlock—— 需要加锁的的读写锁
返回值:加锁成功返回0;否则返回错误编号。
如果线程不希望被阻塞,可用调用如下函数进行尝试加锁,不可以获取锁时,这两个函数都返回EBUSY。
int pthread_rwlock_tryrdlock( pthread_ rwlock_t * rwlock);//读
int pthread_rwlock_trywrlock( pthread_ rwlock_t * rwlock);//写
参数说明:
rwlock—— 需要尝试加锁的读写锁
返回值:加锁成功返回0;否则返回EBUSY。
与互斥量一样,Single NUIX Specification 提供了带有超时的读写锁加锁函数,使应用程序在获取读写锁时避免陷入永久阻塞状态。当线程试图访问一个已经加锁的读写锁时,如下函数允许设定线程阻塞时间。这两个函数与pthread_ rwlock_rdlock()和pthread_ rwlock_wrlock()函数基本上是等价的,但是在达到超时时间值时不会对读写锁进行加锁,而是返回错误码ETIMEOUT。
int pthread_rwlock_timedrdlock( pthread_ rwlock_t *restrict rwlock,
const struct timespec *restrict tsptr );
int pthread_rwlock_timedwrlock( pthread_ rwlock_t *restrict rwlock,
const struct timespec *restrict tsptr );
参数说明:
rwlock—— 需要加锁的读写锁
tsptr —— 超时时间,线程愿意等待的绝对时间(与相对时间对比而言,指定在时间X之前可以等待,而不是愿意阻塞Y秒),用timespec结构来表示的(用秒和纳秒来描述时间)。
返回值:加锁成功返回0;否则返回EBUSY。
- 解锁
线程对读写锁访问结束,需要调用如下函数对读写锁进行解锁。下列行为均属于错误应该避免:对未加锁的信号量解锁,解锁其他线程锁定的读写锁。
int pthread_rwlock_unlock( pthread_ rwlock_t * rwlock);
参数说明:
rwlock—— 需要解锁的读写锁
返回值:解锁成功返回0;否则返回错误编号。
三:注意
- 包含头文件:#include<pthread.h>
- 由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread,所以在编译中要加-lpthread参数eg:
gcc -o test1 -lpthread test1.c
四:示例
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define COUNT_MAX 520
pthread_rwlock_t rwlock;
int m_Count=0;
void *pth_wr(void *arg)
{
int i = (int)arg;
while (m_Count <= COUNT_MAX)
{
pthread_rwlock_wrlock(&rwlock);//请求写锁
printf("write================全局变量m_Count = %d, 我是%d号线程。\n", m_Count += 40, i + 1);
pthread_rwlock_unlock(&rwlock);//解锁
sleep(1);
}
return NULL;
}
void *pth_rd(void *arg)
{
int i = (int)arg;
while (m_Count <= COUNT_MAX)
{
pthread_rwlock_rdlock(&rwlock);//请求读锁
printf("read=================全局变量m_Count = %d, 我是%d号线程。\n", m_Count, i + 1);
pthread_rwlock_unlock(&rwlock);//解锁
sleep(1);
}
return NULL;
}
int main(void)
{
pthread_t pth[10];
int i,j;
pthread_rwlock_init(&rwlock, NULL);
for (i = 0; i != 5; i++)//写
{
pthread_create(&pth[i], NULL, pth_wr, (void *)i);
}
for (i = 0; i != 5; i++)//读
{
pthread_create(&pth[5 + i], NULL, pth_rd, (void *)i);
}
while(1)
{
if (m_Count >= COUNT_MAX)
{
for (j = 0; j != 10; j++)
{
pthread_join(pth[j], NULL);//回收线程
}
break;
}
}
return 0;
}