ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

读写锁 pthread_rwlock

2020-03-09 12:53:17  阅读:276  来源: 互联网

标签:__ rwlock 写锁 读写 读锁 pthread nr


一. 什么是读写锁

   很多时候,对共享变量的访问有以下特点:大多数情况下线程只是读取共享变量的值,并不修改,只有极少数情况下,

线程才会真正地修改共享变量的值。对于这种情况,读请求之间之间是无需同步的,他们之间的并发访问是安全的。但是

必须互斥写请求和其他读请求。
  这种情况在实际中是存在的,比如配置项。大多数时间内,配置是不会发生变化的,偶尔会出现修改配置的情况。如果

使用互斥量,完全阻止读请求并发,则会造成性能的损失。处于这种考虑,POSIX引入了读写锁。

 

二. 读写锁API

  1. 读写锁属性

    读写锁属性(pthread_rwlockattr_t)有两种: lockkind和pshared。

    (1)lockkind:读写策略,包括读取优先(默认属性)、写入优先。

    读取优先:如果在写锁请求后面到来的读锁请求不被写锁请求阻塞。如果读锁请求前仆后继源源不断地到来,只要有

        一个读锁没完成,写锁就没分。 该策略会导致较早到的写锁饿死

    写入优先:一旦线程申请写锁,在写锁请求后面到来的读锁请求就会统统被阻塞,不能先于写请求拿到锁。

enum
{
PTHREAD_RWLOCK_PREFER_READER_NP, //读者优先(默认属性)
PTHREAD_RWLOCK_PREFER_WRITER_NP, //读者优先
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, //写者优先
PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP //读者优先
};
/* 获取与设置属性 */
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t * attr, int * pref);
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t * attr, int * pref);

 

     (2)pshared 

    PTHREAD_PROCESS_PRIVATE: 进程内 竞争读写锁 -- 默认属性

    PTHREAD_PROCESS_PUBLIC:   进程间  竞争读写锁 

// 设置pshared属性
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
// 获取pshared属性
int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *attr, int *pshared);

 

  1. 创建

int pthread_rwlock_init(pthread_rwlock_t *rwlock,  const pthread_rwlockattr_t *attr);

pthread_rwlock_t  rwlock = PTHREAD_RWLOCK_INITIALIZER

  2. 获取

int pthread_rwlock_rdlock(pthread_rwlock_t *rwptr)  //读锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwptr)  //写锁

  3. 释放

int pthread_rwlock_unlock(pthread_rwlock_t *rwptr)  //将读锁或写锁解锁

  4. 销毁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

 

三. 读写锁实现原理

变量  说明
__lock 管理读写锁全局竞争的锁,无论是读锁写锁还是解锁,都会互斥
__writer 写锁持有者的线程ID,如果为0则表示当前无线程持有写锁
__nr_reads 读锁持有线程的个数
__nr_reads_queued 读锁的派对等待线程的个数
__nr_writers_queued 写锁的排队等待线程的个数

  无论是申请读锁还是申请写锁,还是解锁,都至少会做一次全局互斥锁(对应__lock)的加锁和解锁,若不考虑阻塞,单单考虑

操作本身的开销,读写锁的加解锁开销是互斥锁的两倍。当然,函数结束前或进入阻塞之前,会将全局的互斥锁释放。

1. 对于读锁请求而言,如果:

    (I) 无线程持有写锁,即__writer==0

    (II) 采用的是读者优先策略或没有写锁的等待者(__nr_writers_queued==0)

  当满足这两个条件时,读锁请求都可以立即获得读锁,返回之前执行__nr_readers++,表示增加了一个线程占有读锁。

  不满足的话,则执行__nr_readers_queued++,表示增加一个读锁等待者,然后调用futex,陷入阻塞。醒来之后,会执行

__nr_readers_queued–,然后再次判断是否同时满足条件1和2

2. 对于写锁请求而言,如果:

    (I) 无线程持有写锁,即__writer==0

    (II) 没有线程持有读锁,即__nr_readers==0

  只要满足上述条件,就会立刻拿到写锁,将__writer置为线程的ID(调度域)

  如果不满足,那么执行__nr_writers_queued++,表示增加一个写锁等待者线程,然后执行mutex陷入等待。醒来后,先执行

__nr_writers_queued–,然后重新判断条件1和2。

3. 对于解锁而言,如果当前锁是写锁,则执行如下操作:

    执行__writer=0,表示释放写锁

    根据__nr_writers_queued判断有没有写锁等待者,如果有则唤醒一个写锁等待者

 如果没有写锁等待者,则判断有没有读锁等待者;如果有,则将所有的读锁等待者一起唤醒。

 如果当前锁是读锁,则执行如下操作:

    执行__nr_readers–,表示读锁占有者少了一个

    判断__nr_readers是否等于0,是的话则表示自己是最后一个读锁占有者,需要唤醒写锁等待者或者读锁等待者:

    根据__nr_writers_queued判断是否存在写锁等待者,若有,则唤醒一个写锁等待线程
    如果没有写锁等待者,判断是否存在读锁等待者,若有,则唤醒所有的读锁等待者

标签:__,rwlock,写锁,读写,读锁,pthread,nr
来源: https://www.cnblogs.com/blackandwhite/p/12447522.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有