在Win32平台中,多读单写锁如何使用临界区实现?

--------------------------------------------------------------------------------
标题: 在Win32平台中,多读单写锁如何使用临界区实现?
作者: 叶飞虎
日期: 2011.11.11
--------------------------------------------------------------------------------

   在多线程编程中,读写锁主要应用于写数据相对比较少,而读比较多,同时要求并发性
比较高的时候。

 

现给出使用临界区的读写锁代码,如下:

class TKYLockRWEx
{
public:
   TKYLockRWEx();
   virtual ~TKYLockRWEx();

   bool              LockRead();
   bool              LockWrite();

   bool              TryLockRead();
   bool              TryLockWrite();

   void              UnlockRead();
   void              UnlockWrite();

private:
   void              Lock()            { EnterCriticalSection(&FRWLock); }
   void              Unlock()          { LeaveCriticalSection(&FRWLock); }

   void              WaitingReader()   { EnterCriticalSection(&FLockReader); }
   void              WaitingWriter()   { EnterCriticalSection(&FLockWriter); }

   inline void       SetReadSignal();
   inline void       SetWriteSignal();

private:
   CRITICAL_SECTION  FRWLock;
   CRITICAL_SECTION  FLockReader;
   CRITICAL_SECTION  FLockWriter;
   long              FReadingCount;
   long              FWritingCount;
   long              FWaitingReadCount;
   long              FWaitingWriteCount;
};

// ---------------- 构造函数和析构函数 ----------------
// 构造函数
TKYLockRWEx::TKYLockRWEx()
{
   // 初始化
   FReadingCount     = 0;
   FWritingCount     = 0;
   FWaitingReadCount = 0;
   FWaitingWriteCount= 0;

   // 创建临界区和读写者
   InitializeCriticalSection(&FRWLock);
   InitializeCriticalSection(&FLockReader);
   InitializeCriticalSection(&FLockWriter);
}

// 析构函数
TKYLockRWEx::~TKYLockRWEx()
{
   // 置释放标志
   Lock();
   bool bWaiting = (FReadingCount > 0) || (FWritingCount == 1)
                                       || (FWaitingReadCount > 0)
                                       || (FWaitingWriteCount > 0);
   FReadingCount = -1;
   Unlock();

   // 等待一会儿
   if (bWaiting)
      Sleep(10);

   // 释放临界区和读写者
   DeleteCriticalSection(&FLockWriter);
   DeleteCriticalSection(&FLockReader);
   DeleteCriticalSection(&FRWLock);
}

// ---------------- 私有方法 ----------------
// 设置读信号
inline void TKYLockRWEx::SetReadSignal()
{
   // FWritingCount 作为读信号广播的个数
   if (FWritingCount == 0)
      FWritingCount = -FWaitingReadCount;

   // 是否需要继续广播
   if (FWritingCount < 0)
   {
      FWritingCount++;
      FReadingCount++;
      FWaitingReadCount--;

      LeaveCriticalSection(&FLockReader);
   }
   else if (FWaitingWriteCount == 0)   // 全部已退出锁
   {
      LeaveCriticalSection(&FLockReader);
      LeaveCriticalSection(&FLockWriter);
   }
}

// 设置写信号
inline void TKYLockRWEx::SetWriteSignal()
{
   FWritingCount = 1;
   FWaitingWriteCount--;

   LeaveCriticalSection(&FLockWriter);
}

// ---------------- 公有方法 ----------------
// 读加锁
bool TKYLockRWEx::LockRead()
{
   bool result   = true;
   bool bWaiting = false;

   // 读数加 1
   Lock();
   if (FReadingCount == -1)      // 释放标志
      result   = false;
   else if ((FWritingCount == 1) || (FWaitingWriteCount > 0))
   {
      FWaitingReadCount++;
      bWaiting = true;
   }
   else if (++FReadingCount == 1)
   {
      WaitingWriter();
      WaitingReader();
   }
   Unlock();

   // 判断是否等待读信号
   if (bWaiting)
   {
      // 等待读信号
      WaitingReader();

      // 若广播个数不为零则继续置信号
      Lock();
      if (FWritingCount < 0)
         SetReadSignal();
      Unlock();
   }

   // 返回结果
   return result;
}

// 写加锁
bool TKYLockRWEx::LockWrite()
{
   bool result   = true;
   bool bWaiting = false;

   // 写数置 1
   Lock();
   if (FReadingCount == -1)      // 释放标志
      result   = false;
   else if ((FWritingCount == 1) || (FReadingCount > 0))
   {
      FWaitingWriteCount++;
      bWaiting = true;
   }
   else
   {
      FWritingCount = 1;
      WaitingWriter();
      WaitingReader();
   }
   Unlock();

   // 判断是否等待写信号
   if (bWaiting)
      WaitingWriter();

   // 返回结果
   return result;
}

// 读试着加锁
bool TKYLockRWEx::TryLockRead()
{
   bool result = true;

   // 读数加 1
   Lock();
   if ((FReadingCount == -1) || (FWritingCount == 1)
                             || (FWaitingWriteCount > 0))
      result = false;
   else if (++FReadingCount == 1)
   {
      WaitingWriter();
      WaitingReader();
   }
   Unlock();

   // 返回结果
   return result;
}

// 写试着加锁
bool TKYLockRWEx::TryLockWrite()
{
   bool result = true;

   // 写数置 1
   Lock();
   if ((FReadingCount == -1) || (FWritingCount == 1)
                             || (FReadingCount > 0))
      result = false;
   else
   {
      FWritingCount = 1;
      WaitingWriter();
      WaitingReader();
   }
   Unlock();

   // 返回结果
   return result;
}

// 读解锁
void TKYLockRWEx::UnlockRead()
{
   Lock();
   if (FReadingCount > 0)
   {
      // 读数减 1
      FReadingCount--;

      // 置读/写信号
      if (FReadingCount == 0)
      {
         if (FWaitingWriteCount > 0)
            SetWriteSignal();
         else
            SetReadSignal();
      }
   }
   Unlock();
}

// 写解锁
void TKYLockRWEx::UnlockWrite()
{
   Lock();
   if (FWritingCount == 1)
   {
      // 写数置 0
      FWritingCount = 0;

      // 置读/写信号
      if (FWaitingWriteCount > FWaitingReadCount)
         SetWriteSignal();
      else
         SetReadSignal();
   }
   Unlock();
}



注:
    使用临界区的读写锁代码是从使用 Event 的 TKYLockRW 类更改而来, 未经验证是否正
确, 本人只是从逻辑上确认没有bug, 倘若真的存在 bug, 欢迎拍砖指正!

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值