linux c 读写锁pthread_rwlock
作用:防止多个线程同时对同一数据进行读写导致数据混乱,在读写这个数据前获取读写锁就行了
写写互斥,读写互斥,读读允许,同线程读写死锁
1.写写互斥
一个线程获取了写锁,另一个线程再获取写锁将会阻塞
2.读写互斥
一个线程获取了读锁,另一个线程再获取写锁时将阻塞,反之亦然
3.读读允许
在其他线程没获取写锁时,任意数量的线程都可以获取读锁
4.同线程读写死锁
2的衍生
函数:
//定义且初始化互斥量
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
获取读锁
pthread_rwlock_rdlock(&rwlock);
获取写锁
pthread_rwlock_wrlock(&rwlock);
释放读锁
pthread_rwlock_unlock(&rwlock);
常用场景
#include "stdio.h"
#include "unistd.h"
#include "pthread.h"
#include "string.h"
//定义且初始化互斥量
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
//线程1
void* task1(void* p)
{
printf("thread %d getting rdlock\n", pthread_self());
pthread_rwlock_rdlock(&rwlock);//获取读锁
printf("thread %d got rdlock!\n", pthread_self());
sleep(5);
pthread_rwlock_unlock(&rwlock);//释放读锁
printf("thread %d release rdlock\n", pthread_self());
return NULL;
}
int main()
{
pthread_t thread;
pthread_create(&thread, NULL, task1, NULL);
pthread_create(&thread, NULL, task1, NULL);
pthread_create(&thread, NULL, task1, NULL);//开启三个线程
sleep(1);//等待子线程先获取读写锁
printf("thread %d getting wrlock\n", pthread_self());
pthread_rwlock_wrlock(&rwlock);
printf("thread %d got wrlock!\n", pthread_self());
return 0;
}
运行结果
可以看到主线程在三个子线程的读锁释放后才成功获取写锁
写饥饿现象:
当持续不断的有新的线程获取读锁又释放,就可能会出现一个现象,因为读读允许,所有可能会很长时间一直有不同的线程正在读,这样写入线程一直无法获取到写锁,这就是写饥饿,可以通过初始化设置将该读写锁设置为:有线程在写阻塞时新的读锁获取也阻塞。
这样就不会有新的线程获取读锁,等当前存在的读锁都释放后写线程就得以运行。
pthread_rwlockattr_t rwlockattr;//读写锁属性变量
pthread_rwlockattr_init(&rwlockattr);//初始化读写锁属性变量
pthread_rwlockattr_setkind_np(&rwlockattr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
);//初始化读写锁属性调度策略设为写优先
pthread_rwlock_t rwlock;//读写锁
pthread_rwlock_init(&rwlock, &rwlockattr);//读写锁以读写锁属性变量初始化