- 概述
在某些场景下,读数据操作比写数据操作要频繁,那么可以使用读写锁替代互斥锁来提高应用程序的性能。
读写锁的访问规则如下:
- 多个线程共享读操作权限
- 没有读或者写操作时,才可以执行写操作
- 主要操作
#include <pthread.h>
int pthread_rwclock_rdclock(pthread_rwlock_t *rwptr);//加读出锁,如果读写锁被一个写入者持有则堵塞
int pthread_rwclock_wrclock(pthread_rwlock_t *rwptr);//加写入锁,如果读写锁被读或者写线程占有,则堵塞等待
int pthread_rwclock_unclock(pthread_rwlock_t *rwptr);//释放锁
// 非阻塞模式,如果不能马上得到就返回一个EBUSY错误
int pthread_rwclock_tryrdclock(pthread_rwlock_t *rwptr);
int pthread_rwclock_trywrclock(pthread_rwlock_t *rwptr);
读写锁的初始化和销毁
int pthread_rwclock_init(pthread_rwlock_t *rwptr, const pthread_rwlockattr_t *attr);
int pthread_rwclock_destory(pthread_rwlock_t *rwptr);
设置读写锁属性,属性值为PTHREAD_PROCESS_PRIVATE或 PTHREAD_PROCESS_SHARED。前者表是读写锁只在本进程可用,后者表示可以多进程共享。
int pthread_rwclock_getpshared(const pthread_rwlockattr_t *attr, int *valptr);
int pthread_rwclock_setpshared(const pthread_rwlockattr_t *attr, int valptr);
- 举例
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
long g_data = 0;
pthread_rwlock_t lock; //读写锁
void* wr_cb(void* arg) {
while (1) {
//加写入锁
pthread_rwlock_wrlock(&lock);
g_data++;
usleep(10);
printf("write clock, thread id: %lu, data: %d\n", pthread_self(),
g_data);
//释放锁
pthread_rwlock_unlock(&lock);
usleep(1000);
}
return NULL;
}
void* rd_cb(void* arg) {
while (1) {
//加读出锁
pthread_rwlock_rdlock(&lock);
printf("read clock, thread id: %lu, data: %d\n", pthread_self(),
g_data);
//释放锁
pthread_rwlock_unlock(&lock);
usleep(1000);
}
return NULL;
}
int main(int argc, char* argv[]) {
pthread_t thd[4]; // 4个线程
pthread_create(&thd[0], NULL, wr_cb, NULL);
pthread_create(&thd[1], NULL, wr_cb, NULL);
pthread_create(&thd[2], NULL, rd_cb, NULL);
pthread_create(&thd[3], NULL, rd_cb, NULL);
int i;
for (i = 0; i < 4; i++) {
pthread_join(thd[i], NULL);
}
//销毁
pthread_rwlock_destroy(&lock);
return 0;
}
- 总结
读写锁的特性
- 加读出锁: 来了N个线程做读出操作,那么都加锁成功, 这叫读锁共享。如果先来了M个线程做读出操作,后来了K个线程做写入操作,又来了L个线程做读操作。那么从K个线程开始阻塞。后面即便L个线程是读操作也不可,这里顺序的一致性。
- 加写入锁,当线程T加锁成功时,其他任何线程都有阻塞,这样写锁独占
- 线程R加读锁,线程W加写锁,如果同时到达,那么写锁优先。