pthread中读写锁
读写锁很像一个互斥量,他阻止多个线程同时修改共享数据的另一种方法,区分不同互斥量的是他是分读数据和写数据,一个读写锁允许同时多个线程读数据,只要他们不修改数据。
- 只要没有写模式下的加锁,任意线程都可以进行读模式下的加锁这个其实可以很好理解,因为单纯的读操作不改变访问的任何资源,多个线程都可以同时无影响的读取资源。
- 只有读写锁处于不加锁状态时,才能进行写模式下的加锁
读写锁也称为共享-(shared-exclusive)独占锁,当读写锁以读模式加锁时,它是以共享模式锁住(即任何访问者都可以使用),当以写模式加锁时,它是以独占模式锁住(只有获得锁的人可以使用)
当一个写锁被释放时,如果读数据写数据同时等待,读数据有优先访问权限。
读写锁的类型是在内存中分配的,当读写锁是在单个进程内的各个线程共享时(默认情况),这些变量可以在进程内;当这些变量是在某个共享内存区的进程间共享时(假设指定PTHREAD_PROCESS_SHARED),这些变量在共享内存中
读数据的频率远大于写数据的频率的应用中。这样可以在任何时刻运行多个读线程并发的执行,给程序带来了更高的并发度。
与互斥锁的区别
- 互斥锁会把试图进入已保护的临界区的线程都阻塞,即同时只有一个线程持有锁
- 读写锁会根据当前进入临界区的线程是读还是写的属性来判断是否允许线程进入。
- 多个读者可以同时持有锁
初始化和销毁
/* 用于初始化读写锁,并可以设置读写锁属性, * 一般默认为NULL,如果要修改写锁属性可以详细参考链接 * http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032t/index.html * PTHREAD_RWLOCK_INITIALIZER宏定义可以用来静态的分配初始一个读写锁,不需要错误检查,分配默认 * 的读写锁属性,和pthread_rwlock_init()指定NULL属性的效果是一致的。pthread_rwlock_destroy() * 用于销毁读写锁。 */ pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; int pthread_rwlock_init(pthread_rwlock_t * restrict lock,const pthread_rwlockattr_t * restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *lock);
init返回值
- 成功返回0
- [EAGAIN]:系统缺少资源来初始化读写锁
- [EBUSY]:尝试初始化一个已经初始化但还未销毁的锁.
- [EINVAL]:attr不可用.
- [ENOMEM]:内存资源不足
destroy返回值
- 成功返回0
- [EBUSY] 尝试销毁一个还锁着的锁
- [EINVAL] 指定的锁参数不可用
读加锁
int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t * restrict lock,const struct timespec * restrict abstime);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *lock);
/* 读写锁读加锁有3个函数接口,pthread_rwlock_rdlock()请求一个读锁,
* 如果当前没有写线程持有锁或者没有写线程阻塞在取锁时则可以立刻获取到锁。否则请求锁的线程阻塞等
* 待,pthread_rwlock_timedrdlock() 执行同样的读加锁操作,只是有个超时时间,在指定abstime时间
*(超时指定的是绝对时间,不是相对时间)获取不到直接返回,其中abstime的类型为struct timespec
*/
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
/* pthread_rwlock_tryrdlock()执行同样加锁操作的非阻塞函数,获不到锁立即返回。
注:一个线程可能获取到多个并发的读锁,如果是这样的话,对每个加锁都要释放一次。
*/
成功均返回0 失败 1.pthread_rwlock_tryrdlock():[EBUSY]其写锁正被持有或者写锁阻塞等待 2.pthread_rwlock_timedrdlock():[ETIMEDOUT]加锁超时 3.pthread_rwlock_rdlock(), pthread_rwlock_timedrdlock(), and pthread_rwlock_tryrdlock():[EAGAIN]获取锁的数量已经超过最大值,[EDEADLK]当前线程已经持有写锁,[EINVAL]指定的锁参数不可用
写加锁
int pthread_rwlock_wrlock(pthread_rwlock_t *lock); //阻塞的形式获取一个写锁 int pthread_rwlock_timedwrlock(pthread_rwlock_t * restrict lock,const struct timespec * restrict abstime); //执行相同的取写锁的操作, 只是有个超时时间,在指定abstime绝度时间内获取不到直接返回 int pthread_rwlock_trywrlock(pthread_rwlock_t *lock); //执行同样加锁操作的非阻塞函数,获不到锁立即返回。
成功均返回0 失败
1.The pthread_rwlock_trywrlock():[EBUSY]不能非阻塞的获得锁 2.pthread_rwlock_timedwrlock():[ETIMEDOUT]加锁超时 3.pthread_rwlock_wrlock(), pthread_rwlock_timedwrlock(), and pthread_rwlock_trywrlock():[EDEADLK]调用的线程已经持有读写锁了,[EINVAL]指定的锁参数不可用
解锁
int pthread_rwlock_unlock(pthread_rwlock_t *lock);// 改函数用来释放获取到的读写锁。
成功均返回0 失败 1.[EINVAL]指定的锁参数不可用 2.[EPERM]当前线程没有持有锁
用互斥量实现读写锁
//rwlock.h
#include <pthread.h>
typedef struct rwlock_tag
{
pthread_mutex_t mutex;
pthread_cond_t r;//读存取
pthread_cond_t w;//写存取
int valid;//检测普通的语法错误,如试图加锁一个没有初始化的读写锁
int r_active;//读线程活跃
int w_active;//写线程活跃
int r_wait;//读线程等待数
int w_wait;//写线程等待数
}rwlock_t;
#define RWL_INITIALIZER \
{ \
PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER, \
PTHREAD_COND_INITIALIZER,RWLOCK_VALID,,,, \
}
#define RWLOCK_VALID 0xfacade
int rwl_init(rwlock_t* rwlock);
int rwl_destroy(rwlock_t* rwlock);
int rwl_readlock(rwlock_t* rwlock);
int rwl_readtrylock(rwlock_t* rwlock);
int rwl_readunlock(rwlock_t* rwlock);
int rwl_writelock(rwlock_t* rwlock);
int rwl_writetrylock(rwlock_t* rwlock);
int rwl_writeunlock(rwlock_t* rwlock);
/*
*rwlock.c
*实现了rwlock.h中的各个函数
*/
#include <pthread.h>
#include "errors.h"
#include "rwlock.h"
int rwl_init(rwlock_t *rwl)//初始化读写锁
{
rwl->r_active=rwl->w_active=;
rwl->r_wait=rwl->w_wait=;
int status=pthread_mutex_init(&rwl->mutex,NULL);
if(status)
return status;
status=pthread_cond_init(&rwl->r,NULL);
if(status)
{
pthread_mutex_destroy(&rwl->mutex);
return status;
}
status=pthread_cond_init(&rwl->w,NULL);
if(status)
{
pthread_cond_destroy(&rwl->r);
pthread_mutex_destroy(&rwl->mutex);
return status;
}
rwl->valid=RWLOCK_VALID;
;
}
int rwl_destroy(rwlock_t *rwl)//释放读写锁
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
//check whether any threads own the lock or
//whether any thread known to be waiting
||rwl->w_active>)||
(rwl->r_wait>||rwl->w_wait>))
{
pthread_mutex_unlock(&rwl->mutex);
return EBUSY;
}
rwl->valid=;
status=pthread_mutex_unlock(&rwl->mutex);
if(status)
return status;
status=pthread_mutex_destroy(&rwl->mutex);
int status1=pthread_cond_destroy(&rwl->r);
int status2=pthread_cond_destroy(&rwl->w);
?status:(status1!=?status1:status2);
}
//cleanup when the reads clock condition variable wait canceled.
//record that the thread is no longer waiting,and unlock the mutex.
static void rwl_readcleanup(void *arg)//read/write is a cancel point
{
rwlock_t *rwl=(rwlock_t*)arg;
rwl->r_wait--;
pthread_mutex_unlock(&rwl->mutex);
}
//cleanup when the write lock condition variable wait is canceled.
//record that the thread is no longer waiting and unlock the mutex.
static void rwl_writecleanup(void* arg)
{
rwlock_t* rwl=(rwlock_t*)arg;
rwl->w_wait--;
pthread_mutex_unlock(&rwl->mutex);
}
//lock a reads/write for reads access. write thread priority. this is very important!!!
int rwl_readlock(rwlock_t* rwl)
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
if(rwl->w_active)
{
rwl->r_wait++;
pthread_cleanup_push(rwl_readcleanup,(void*)rwl);
while(rwl->w_active)
{
status=pthread_cond_wait(&rwl->r,&rwl->mutex);//wait reads
if(status)
return status;
}
pthread_cleanup_pop();
}
)
rwl->r_active++;
pthread_mutex_unlock(&rwl->mutex);
return status;
}
int rwl_readtrylock(rwlock_t* rwl)//attempt to lock a read/write lock for read access
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
if(rwl->w_active)
status=EBUSY;
else
rwl->r_active++;
int status1=pthread_mutex_unlock(&rwl->mutex);
?status1:status;
}
int rwl_readunlock(rwlock_t* rwl)
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
rwl->r_active--;
&&rwl->w_wait>)
status=pthread_cond_signal(&rwl->w);//signal write
int status1=pthread_mutex_unlock(&rwl->mutex);
?status:status1;
}
int rwl_writelock(rwlock_t* rwl)
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
)
{
rwl->w_wait++;
pthread_cleanup_push(rwl_writecleanup,(void*)rwl);
)
{ //wait write
status=pthread_cond_wait(&rwl->w,&rwl->mutex);
if(status)
break;
}
pthread_cleanup_pop();
rwl->w_wait--;
}
)
rwl->w_active=;
pthread_mutex_unlock(&rwl->mutex);
return status;
}
int rwl_writetrylock(rwlock_t* rwl)
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
)
status=EBUSY;
else
rwl->w_active=;
int status1=pthread_mutex_unlock(&rwl->mutex);
?status:status1;
}
int rwl_writeunlock(rwlock_t* rwl)
{
if(rwl->valid!=RWLOCK_VALID)
return EINVAL;
int status=pthread_mutex_lock(&rwl->mutex);
if(status)
return status;
rwl->w_active=;
)
{
status=pthread_cond_broadcast(&rwl->r);//broadcast reads
if(status)
{
pthread_mutex_unlock(&rwl->mutex);
return status;
}
}
)
{
status=pthread_cond_signal(&rwl->w);//signal write
if(status)
{
pthread_mutex_unlock(&rwl->mutex);
return status;
}
}
status=pthread_mutex_unlock(&rwl->mutex);
return status;
}
//main.c
#include <stdio.h>
#include "rwlock.h"
#include "errors.h"
#define THREADS 5
#define DATASIZE 15
#define INERATIONS 6
typedef struct thread_tag
{
int thread_num;//array index
pthread_t tid;
int updates;
int reads;
int interval;//how many times when exce write.
}thread_t;
typedef struct data_tag
{
rwlock_t lock;
int data;
int updates;
}data_t;
thread_t threads[THREADS];
data_t data[DATASIZE];
void* thread_routine(void* arg)
{
thread_t* self=(thread_t*)arg;
;
;
;
int status;
;i<INERATIONS;++i)
{
)
{
status=rwl_writelock(&data[j].lock);
if(status)
err_abort(status,"write lock");
data[j].data=self->thread_num;
data[j].updates++;
self->updates++;
status=rwl_writeunlock(&data[j].lock);
if(status)
err_abort(status,"write unlok");
}
else
{
status=rwl_readlock(&data[j].lock);
if(status)
err_abort(status,"reads lock");
self->reads++;
if(data[j].data==self->thread_num)
repeats++;
status=rwl_readunlock(&data[j].lock);
if(status)
err_abort(status,"reads unlock");
}
j++;
if(j>=DATASIZE)
j=;
}
)
printf("threads %d found unchanged elements %d times:\n",
self->thread_num,repeats);
return NULL;
}
int main()
{
pthread_setconcurrency(THREADS);
int status;
int i,j;
unsigned ;
;
;
//initialize the share data
;i<DATASIZE;++i)
{
data[i].data=;
data[i].updates=;
status=rwl_init(&data[i].lock);
if(status)
err_abort(status,"Init rwlock");
}
//create threads to access shared data
;j<THREADS;++j)
{
threads[j].thread_num=j;
threads[j].updates=;
threads[j].reads=;
threads[j].interval=rand_r(&seed)%;
status=pthread_create(&threads[j].tid,NULL,thread_routine,(void*)&threads[j]);
if(status)
err_abort(status,"create thread");
}
//wait for all threads to complete,and collect statistics
;j<THREADS;++j)
{
status=pthread_join(threads[j].tid,NULL);
if(status)
err_abort(status,"join threads");
thread_updates+=threads[j].updates;
printf("%02d: interval %d,updates %d,reads %d\n",
j,threads[j].interval,threads[j].updates,threads[j].reads);
}
//collect statistics for the data
;i<DATASIZE;++i)
{
data_updates+=data[i].updates;
printf("data %02d: value %d,%d updates\n",i,data[i].data,
data[i].updates);
rwl_destroy(&data[i].lock);
}
printf("%d threads updates,%d data updates\n",thread_updates,
data_updates);
;
}
写一个Makefile将各个源文件一块编译
下面是执行结果:


pthread中读写锁的更多相关文章
- linux中读写锁的rwlock介绍-nk_ysg-ChinaUnix博客
linux中读写锁的rwlock介绍-nk_ysg-ChinaUnix博客 linux中读写锁的rwlock介绍 2013-02-26 13:59:35 分类: C/C++ http://yaro ...
- Eureka中读写锁的奇思妙想,学废了吗?
前言 很抱歉 好久没有更新文章了,最近的一篇原创还是在去年十月份,这个号确实荒废了好久,感激那些没有把我取消关注的小伙伴. 有读者朋友经常私信问我: "你号卖了?" "文 ...
- 基于pthread实现读写锁
读写锁可用于在多线程访问map等数据结构时使用 #include <pthread.h> class ReadWriteLock { public: ReadWriteLock() { p ...
- Java中读写锁的介绍
读写锁的简单介绍 所谓的读写锁,就是将一个锁拆分为读锁和写锁两个锁,然后你加锁的时候,可以加读锁,也可以加写锁. ReentrantLock lock=new ReentrantLock(); loc ...
- 【C/C++多线程编程之九】pthread读写锁
多线程编程之读写锁 Pthread是 POSIX threads 的简称,是POSIX的线程标准. pthread读写锁把对共享资源的訪问者分为读者和写者,读者仅仅对共享资源 ...
- Unix IPC之读写锁
linux中读写锁的rwlock介绍 读写锁比mutex有更高的适用性,可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁: 1,当读写锁是写加锁状态时, 在这个锁被解锁之前, 所 ...
- 读写锁:ReadWriteLock
http://my.oschina.net/20076678/blog/173165 一.在JDK文档中关于读写锁的相关说明 ReadWriteLock 维护了一对相关的 锁 ,一个用于只读操作, ...
- c++ 读写锁
#ifndef THREAD_UTIL_H #define THREAD_UTIL_H #include <pthread.h> namespace spider { class Auto ...
- 读写锁ReadWriteLock
为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率. Java中读写锁有个接口java.util ...
随机推荐
- android之代码混淆
项目发布之前混淆是必不可少的工作,混淆可以增加别人反编译阅读代码的难度,还可以缩小APK包. Android 中通过ProGuard 来混淆Java代码,仅仅是混淆java代码.它是无法混淆Nativ ...
- guava的事件发布订阅功能
事件的重要性,不用说很重要,在很多时候我们做完一个操作的时候,需要告知另外一个对象让他执行相应操作,比如当用户注册成功的时候,需要抛出一个注册成功的事件,那么有监听器捕获到这个事件,完成后续用户信息初 ...
- 2-5-NFS服务器配置和autofs自动挂载-配置Samba服务器配置现实文件共享
大纲: NFS服务器运行原理 实战配置NFS服务器 配置Samba服务器配置现实文件共享 ----------------------------------------------- 问题: # 怎 ...
- 实现Callable接口创建线程
创建执行线程有四种方式: 实现implements接口创建线程 继承Thread类创建线程 实现Callable接口,通过FutureTask包装器来创建线程 使用线程池创建线程 下面介绍通过实现Ca ...
- Java进阶1. Synchronized 关键字
Java进阶1. Synchronized 关键字 20131025 1.关于synchronized的简介: Synchronized 关键字代表对这个方法加锁,相当于不管那一个线程,运行到这个方法 ...
- MoreEffectiveC++Item35(效率)(条款16-24)
条款16 谨记80-20法则 条款17 考虑使用 lazy evaluation(缓释评估) 条款18 分期摊还预期的计算成本 条款19 了解临时对象的来源 条款20 协助完成"返回值的优化 ...
- Django-RestfulFramework --- DRF
>> (1)RESTful api 规范 和 DRF 的基本介绍 >> (2)DRF 的 认证系统实现 >> (3)DRF 的 权限系统实现 >> (4 ...
- Springboot yml获取系统环境变量的值
注意,这里说的是获取系统环境变量的值,譬如Windows里配置的JAVA_HOME之类的,可以直接在Springboot的配置文件中获取. 我们经常使用一些docker管理平台,如DaoCloud.r ...
- 文件处理工具 gif合成工具 文件后缀批量添加工具 文件夹搜索工具 重复文件查找工具 网页图片解析下载工具等
以下都是一些简单的免费分享的工具,技术支持群:592132877,提供定制化服务开发. Gif动图合成工具 主要功能是扫描指定的文件夹里的所有zip文件,然后提取Zip文件中的图片,并合成一张gif图 ...
- IOS开发 多线程编程 - NSThread
每个iOS应用程序都有个专门用来更新显示UI界面.处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将 ...