读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程。当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步.
和互斥量不同的是:互斥量会把试图进入已保护的临界区的线程都阻塞;然而读写锁会视当前进入临界区的线程和请求进入临界区的线程的属性来判断是否允许线程进入。
相对互斥量只有加锁和不加锁两种状态,读写锁有三种状态:读模式下的加锁,写模式下的加锁,不加锁。
读写锁的使用规则:
只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁;
只有读写锁处于不加锁状态时,才能进行写模式下的加锁;
读写锁也称为共享-独占(shared-exclusive)锁,当读写锁以读模式加锁时,它是以共享模式锁住,当以写模式加锁时,它是以独占模式锁住。读写锁非常适合读数据的频率远大于写数据的频率从的应用中。这样可以在任何时刻运行多个读线程并发的执行,给程序带来了更高的并发度.
读写锁的生成与销毁
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrictrwlock ,const pthread_rwlockattr_t *restrict attr );
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock );
成功返回0, 失败返回错误号
pthread_rwlock_init对读写锁做初始化,参数attr 用于设定Mutex 属性。如果用PTHREAD_RWLOCK_INITIALIZER 初始化全局或者静态Mutex, 那它相当于用pthread_rwlock_init 初始化时attr 为NULL。
读写锁的使用
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock ); //读时加锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock ); //写时加锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock ); //释放锁
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock );
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock );
int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
成功返回0, 失败返回错误号
try类函数加锁:如果获取不到锁,会立即返回错误EBUSY!
timed类函数加锁:如果规定的时间内获取不到锁,会返回ETIMEDOUT错误!
读写锁使用实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#define MAX_SESSION_NUM 1000
int current_session_num = 0;
pthread_rwlock_t session_rwlock = PTHREAD_RWLOCK_INITIALIZER;
int rand_num()
{
return (rand() % 3 + 1);
}
void *get_session_func(void *arg)
{
while (1)
{
pthread_rwlock_rdlock(&session_rwlock);
printf("I got read lock, thread id: %d ...\r\n", (int)pthread_self());
if (current_session_num < MAX_SESSION_NUM && current_session_num > 0)
{
printf("The latest session id is: %d\r\n", current_session_num);
}
else if (current_session_num == 0)
{
printf("No session existes!\r\n");
}
else
{
printf("The session pool is full\r\n");
}
pthread_rwlock_unlock(&session_rwlock);
sleep(rand_num());
}
return (void *)-1;
}
void *write_session_func(void *arg)
{
while (1)
{
pthread_rwlock_wrlock(&session_rwlock);
printf("I got write lock, thread id: %d ...\r\n", (int)pthread_self());
if (current_session_num < MAX_SESSION_NUM && current_session_num >= 0)
{
++current_session_num;
sleep(rand_num());
++current_session_num;
}
else
{
printf("session pool is full ...\r\n");
}
pthread_rwlock_unlock(&session_rwlock);
sleep(rand_num());
}
return (void *)-1;
}
void *remove_session_func(void *arg)
{
while (1)
{
pthread_rwlock_wrlock(&session_rwlock);
printf("I got write lock, thread id: %d ...\r\n", (int)pthread_self());
if (current_session_num < MAX_SESSION_NUM && current_session_num > 0)
{
--current_session_num;
sleep(rand_num());
}
else
{
printf("session pool is empty ...\r\n");
}
pthread_rwlock_unlock(&session_rwlock);
sleep(rand_num());
}
return (void *)-1;
}
int main(int argc, char **argv)
{
pthread_t tid1, tid2, tid3, tid4, tid5;
pthread_create(&tid1, NULL, get_session_func, NULL);
pthread_create(&tid2, NULL, get_session_func, NULL);
pthread_create(&tid3, NULL, get_session_func, NULL);
pthread_create(&tid4, NULL, write_session_func, NULL);
pthread_create(&tid5, NULL, remove_session_func, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_join(tid4, NULL);
pthread_join(tid5, NULL);
return 0;
}