Linux读者写者问题与读写锁
读者写者问题很像生产消费模型,但是消费会把数据拿走,而读不会,因此三种关系:
读者与读者-并发(没关系)
写者和写者-互斥
读者和写者-互斥和同步
一般情况读者很多,写者很少;需要统计读者数量,保证读完再写。
创建和销毁接口:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const
pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
使用接口:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
读写锁行为:
案例:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <cstdlib>
#include <ctime>
// 共享资源
int shared_data = 0;
pthread_rwlock_t rwlock;
// 读者线程函数
void *Reader(void *arg)
{sleep(1); //读者优先,一旦读者进入&&读者很多,写者基本就很难进入了 int number = *(int *)arg;while (true){pthread_rwlock_rdlock(&rwlock); // 读者加锁std::cout << "读者-" << number << " 正在读取数据, 数据是: "<< shared_data << std::endl;sleep(1); // 模拟读取操作pthread_rwlock_unlock(&rwlock); // 解锁}delete (int *)arg;return NULL;
}
// 写者线程函数
void *Writer(void *arg)
{int number = *(int *)arg;while (true){pthread_rwlock_wrlock(&rwlock); // 写者加锁shared_data = rand() % 100; // 修改共享数据std::cout << "写者- " << number << " 正在写入. 新的数据是: "<< shared_data << std::endl;sleep(2); // 模拟写入操作pthread_rwlock_unlock(&rwlock); // 解锁}delete (int *)arg;return NULL;
}
int main()
{srand(time(nullptr) ^ getpid());pthread_rwlock_init(&rwlock, NULL); // 初始化读写锁// 可以更高读写数量配比,观察现象const int reader_num = 2;const int writer_num = 2;const int total = reader_num + writer_num;pthread_t threads[total]; // 假设读者和写者数量相等// 创建读者线程for (int i = 0; i < reader_num; ++i){int *id = new int(i);pthread_create(&threads[i], NULL, Reader, id);}// 创建写者线程for (int i = reader_num; i < total; ++i){int *id = new int(i - reader_num);pthread_create(&threads[i], NULL, Writer, id);}// 等待所有线程完成for (int i = 0; i < total; ++i){pthread_join(threads[i], NULL);}pthread_rwlock_destroy(&rwlock); // 销毁读写锁return 0;
}
当然可以设置读者或者写者优先级:
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int
pref);
/*
pref 共有 3 种选择
PTHREAD_RWLOCK_PREFER_READER_NP (默认设置) 读者优先,可能会导致写者饥饿情况
PTHREAD_RWLOCK_PREFER_WRITER_NP 写者优先,目前有 BUG,导致表现行为和
PTHREAD_RWLOCK_PREFER_READER_NP 一致
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 写者优先,但写者不能递归加锁
*/
读者优先会尽可能允许多个读者同时访问,而不会优先考虑写者,新到达的读者允许进入读区,而写者会被阻塞,直到所有读者读完离开,会导致饥饿问题,写者长时间不能获取写权限。
写者优先相反,当写者请求写入权限时,系统会尽快地让写者进入写入区,即使此时有读者正在读取,一旦有写者到达,所有后续的读者都会被阻塞,直到写者完成写入并离开写入区。写者优先策略可以减少写者等待的时间,但可能会导致读者饥饿(即读者长时间无法获得读取权限),特别是当写者频繁到达时。