Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3569459
  • 博文数量: 205
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7385
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-23 18:56
个人简介

将晦涩难懂的技术讲的通俗易懂

文章分类

全部博文(205)

文章存档

2024年(8)

2023年(9)

2022年(4)

2021年(12)

2020年(8)

2019年(18)

2018年(19)

2017年(9)

2016年(26)

2015年(18)

2014年(54)

2013年(20)

分类: LINUX

2014-07-08 20:15:12


读写锁的实现
——lvyilong316
要实现读写锁,首先要知道读写锁的特性,除了“读者可并发,写者要排它”之外还要考虑避免写者饥饿的问题。综合考虑后可以讲读写锁的实现总结为一下四点:
    1.当已经被施加写锁的时候,读锁写锁都不能在施加(写锁只能锁一次)
    2.当已经被施加读锁时,还可以继续施加读锁,但不能施加写锁
    3.有等待的写者时不能在获取读锁(保证写者优先)
    4.解锁时有如果写者在等待,不能唤醒读者。
我们使用互斥量(mutex)和条件变量来实现读写锁,这也是大多数系统的实现方式。另外本文主要想说明的是读写锁的实现思路,所以这里只实现最基本的三个操作:申请读锁、申请写锁、解锁。而不实现初始化、trylock、销毁锁等操作。

点击(此处)折叠或打开
  1. typedef struct
  2. {
  3.    pthread_mutex_t rw_mutex; //对整个结构体提供互斥访问
  4.    pthread_cond_t rw_condreaders;//用于通知申请读锁的线程
  5.    pthread_cond_t rw_condwriters;//用于通知申请写锁的线程
  6.    int rw_waitreaders; //等待申请读锁的线程数
  7.    int rw_waitwriters; //等待申请写锁的线程数
  8.    int rw_refcount; //表示读写锁的状态,如果是-1表示它是一个写锁
  9.  }pthread_rwlock_t; //0表示它是可用的,大于0表示当前容纳的读锁数量


  10. int pthread_rwlock_rdlock(pthread_rwlock_t *rw) //申请读锁
  11. {
  12.   int result; //返回值(出错状态)

  13.   pthread_mutex_lock(&rw->rw_mutex);
  14.   //当写锁正在使用时不能上读锁,当锁可用但有线程等待申请写锁时样也不能上读锁,这一点体现出来“写者优先”
  15.   while(rw->rw_refcount<0||rw->rw_waitwriters>0)
  16.   {
  17.     rw->rw_waitreaders++;
  18.     result=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);//等待读条件就绪
  19.     rw->rw_waitreaders--;
  20.     if(result!=0)
  21.        break;
  22.   }
  23.   if(result==0)
  24.        rw->rw_refcount++; //又有一个新的线程获取了读锁

  25.   pthread_mutex_unlock(&rw->rw_mutex);
  26.   return (result);
  27. }


  28. int pthread_rwlock_wrlock(pthread_rwlock_t *rw) //申请写锁
  29. {
  30.   int result; //返回值(出错状态)

  31.   pthread_mutex_lock(&rw->rw_mutex);
  32.     //这里只检查锁是否可用
  33.   while(rw->rw_refcount!=0)
  34.  {
  35.    rw->rw_waitwriters++;
  36.    result=pthread_cond_wait(&rw->rw_condwriters,&rw->rw_mutex);//等待写条件就绪
  37.    rw->rw_waitwriters--;
  38.    if(result!=0)
  39.      break;
  40.  }
  41.   if(result==0)
  42.     rw->rw_refcount=-1; //线程获取了写锁

  43.   pthread_mutex_unlock(&rw->rw_mutex);
  44.   return (result);
  45. }




  46. int pthread_rwlock_unlock(pthread_rwlock_t *rw)//释放锁(读锁、写锁)
  47. {
  48.    int result;


  49.   pthread_mutex_lock(&rw->rw_mutex);
  50.   if(rw->refcount>0)
  51.      rw->refcount--;
  52.   else if(rw->refcount==-1)
  53.      rw->refcount=0;
  54.   else
  55.      printf("rw->refcount=%d\n",rw->refcount);
  56.     //先看是否有写者在等待,如果有的话先唤醒写者,这是“写者优先”的另一体现
  57.  if(rw->rw_waitwriters>0)
  58.  {//不能写成if(rw->rw_waitwriters>0&&rw->refcount==0)
  59.    if(rw->refcount==0)
  60.       result=pthread_cond_signal(&rw->rw_condwriters)
  61.  }
  62.  else if(rw->rw_waitreaders>0)
  63.    result=pthread_cond_signal(&rw->rw_condreaders);


  64.   pthread_mutex_unlock(rw->rw_mutex);
  65.   return result;
  66. }
不能写成if(rw->rw_waitwriters>0&&rw->refcount==0)的原因是:
这样会造成写者"饥饿",也就是应当保证,当有写者在等待申请锁的时候,不能在让读者来申请锁,否则由于读者可以多次加锁,一个持续的读请求流可能永远阻塞某个等待的写者。写成if(rw->rw_waitwriters>0&&rw->refcount==0),当第一个条件满足而第二个条件不满足,也就是有写者在等待,而还有读者在使用锁的情况,我们应该仅仅释放一个读锁,别的什么也不做,而这里却会执行else if,导致唤醒等待的读者,使读者获取到锁。
阅读(14231) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~