对象状态类

================================================================================
标题: 对象状态类
作者: 叶飞虎
日期: 2020.01.30


   在多线程编程中,但凡对象的操作必须在某种状态下才有效,且对象状态的变化是需要一
定的时钟周期,这时就涉及状态迁移。利用好对象状态可以提高程序的并发能力,同时也能
控制对象状态。

对象状态类的头文件(KYObjState.h)如下:

// =======================================
// Unit   : 对象状态类
// Version: 4.0.0.0 (build 2020.01.30)
// Author : Kyee Ye
// Email  : kyee_ye(at)126.com
// Copyright (C) Kyee workroom
// =======================================

#ifndef _KYObjState_H_
#define _KYObjState_H_

#include "KYSyncObj.h"

// KYLib 2.0 开始使用 KYLib 命名空间
namespace KYLib
{

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* TKYObjState - 对象状态类 */

class TKYObjState
{
public:
   // 执行结果
   enum TResult
        {orSuccess         =  1,       // 成功
         orFailure         =  0,       // 失败
         orStateInvalid    = -1};      // 状态无效

   // 状态
   enum TState
        {osInactive        = 0,        // 未打开
         osClosing         = 1,        // 正在关闭
         osOpening         = 2,        // 正在打开
         osOpened          = 3,        // 已经打开
         osLogouting       = 4,        // 正在登出
         osLogging         = 5,        // 正在登录
         osLogged          = 6};       // 已登录

   // 回调方法, 注: TDoRet 返回值为 orSuccess 表示成功, 其它值为错误码.
   typedef int  (TObject::*TDoRet)(void* AParam);
   typedef void (TObject::*TDoNone)();

private:
   // 不支持对象拷贝
   TKYObjState(const TKYObjState& obj) {}

public:
   // 构造/析构函数
   TKYObjState();
   ~TKYObjState()                      { Close(true); }

   // 属性
   TState         State() const        { return FState; }   // default: osInactive

   // 设置 DoOpen, DoClose 和 DoInit 回调方法
   bool           SetDoOpen(void* AObject, TDoRet ADoOpen, TDoNone ADoClose,
                                                           TDoNone ADoInit = NULL);

   // 设置 DoLogin 和 DoLogout 回调方法
   // 注: 在此两个回调方法中不允许调用 Close 或 SetClosed 方法, 否则会死循环.
   bool           SetDoLogin(void* AObject, TDoRet ADoLogin, TDoNone ADoLogout);

   // 引用计数加/减 1
   bool           IncRefCountGE(TState AState); // 当 FState >= AState 时引用计数加 1
   bool           IncRefCount(TState AState);   // 当 FState == AState 时引用计数加 1
   bool           IncRefCount()        { return IncRefCountGE(osOpened); }
   void           DecRefCount()        { InterlockedDecrement(&FRefCount); }

   // 打开/关闭/设置已关闭(不执行 DoClose 回调)
   // 注: AParam 参数用于传入 DoOpen 回调方法
   int            Open(void* AParam = NULL);
   void           Close(bool ANeedWait = false);
   void           SetClosed();

   // 登录/登出
   // 注: AParam 参数用于传入 DoLogin 回调方法
   int            Login(void* AParam = NULL);
   void           Logout();

   // 加锁/解锁
   void           Lock()               { FLock.Enter(); }
   void           Unlock()             { FLock.Leave(); }

protected:
private:
   // 执行关闭/登出
   void           DoClose(bool ANeedClose);
   void           DoLogout()           { if (FDoLogout != NULL) (FObjLogin->*FDoLogout)(); }

private:
   TKYCritSect    FLock;               // 状态锁
   TState         FState;              // 状态
   int            FRefCount;           // 状态引用计数
   Longword       FCloseThreadID;      // 当前正在 Close 的线程ID

   // 执行打开/关闭的方法
   TObject*       FObjOpen;            // FDoOpen 和 FDoClose 方法的对象
   TDoRet         FDoOpen;             // 执行打开的回调方法
   TDoNone        FDoClose;            // 执行关闭的回调方法
   TDoNone        FDoInit;             // 执行关闭后初始化的回调方法

   // 执行登录/加载/登出的方法
   TObject*       FObjLogin;           // FDoLogin和 FDoLogout 方法的对象
   TDoRet         FDoLogin;            // 执行登录的回调方法
   TDoNone        FDoLogout;           // 执行登出的回调方法
};

}

#endif

对象状态类的代码文件(KYObjState.cpp)如下:

// =======================================
// Unit   : 对象状态类
// Version: 4.0.0.0 (build 2020.01.30)
// Author : Kyee Ye
// Email  : kyee_ye(at)126.com
// Copyright (C) Kyee workroom
// =======================================

#include "KYObjState.h"

// KYLib 2.0 开始使用 KYLib 命名空间
namespace KYLib
{

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/* TKYObjState - 对象状态类 */

// ---------------- 静态常量 ----------------

// 成功返回值
static const int _Bool_Ret[2] = {TKYObjState::orStateInvalid, TKYObjState::orSuccess};

// ---------------- 构造函数和析构函数 ----------------
// 构造函数
TKYObjState::TKYObjState()
{
   FState         = osInactive;
   FRefCount      = 0;
   FCloseThreadID = 0;

   FObjOpen       = NULL;
   FDoOpen        = NULL;
   FDoClose       = NULL;
   FDoInit        = NULL;

   FObjLogin      = NULL;
   FDoLogin       = NULL;
   FDoLogout      = NULL;
}

// ---------------- 私有函数 ----------------
// 执行关闭
void TKYObjState::DoClose(bool ANeedClose)
{
   // 判断是否需要关闭
   if (ANeedClose && FDoClose != NULL)
      (FObjOpen->*FDoClose)();

   // 等待 RefCount == 0
   while (FRefCount > 0)
      Sleep(8);

   // 执行初始化
   if (FDoInit != NULL)
      (FObjOpen->*FDoInit)();
}

// ---------------- 公有函数 ----------------
// 设置 DoOpen, DoClose 和 DoInit 回调方法
bool TKYObjState::SetDoOpen(void* AObject, TDoRet ADoOpen, TDoNone ADoClose, TDoNone ADoInit)
{
   // 初始化
   bool result = false;

   // 判断 ADoOpen 非空
   if (ADoOpen != NULL)
   {
      Lock();
      if (FState == osInactive)
      {
         FObjOpen = (TObject*)AObject;
         FDoOpen  = ADoOpen;
         FDoClose = ADoClose;
         FDoInit  = ADoInit;
         result   = true;
      }
      Unlock();
   }

   // 返回结果
   return result;
}

// 设置 DoLogin 和 DoLogout 回调方法
// 注: 在此两个回调方法中不允许调用 Close 或 SetClosed 方法, 否则会死循环.
bool TKYObjState::SetDoLogin(void* AObject, TDoRet ADoLogin, TDoNone ADoLogout)
{
   // 初始化
   bool result = false;

   // 判断 ADoLogin 非空
   if (ADoLogin != NULL)
   {
      Lock();
      if (FState == osInactive)
      {
         FObjLogin   = (TObject*)AObject;
         FDoLogin    = ADoLogin;
         FDoLogout   = ADoLogout;
         result      = true;
      }
      Unlock();
   }

   // 返回结果
   return result;
}

// 引用计数加 1, 当 FState >= AState 时引用计数加 1
bool TKYObjState::IncRefCountGE(TState AState)
{
   // 初始化
   bool result = false;

   // 引用计数加 1
   InterlockedIncrement(&FRefCount);
   if (FState >= AState)
      result = true;
   else
      InterlockedDecrement(&FRefCount);

   // 返回结果
   return result;
}

// 引用计数加 1, 当 FState == AState 时引用计数加 1
bool TKYObjState::IncRefCount(TState AState)
{
   // 初始化
   bool result = false;

   // 引用计数加 1
   InterlockedIncrement(&FRefCount);
   if (FState == AState)
      result = true;
   else
      InterlockedDecrement(&FRefCount);

   // 返回结果
   return result;
}

// 打开
int TKYObjState::Open(void* AParam)
{
   // 初始化
   Longword lwThread = GetCurrentThreadId();
   bool     boolNext = false;
   int      result   = orFailure;

   // 更改状态
   Lock();
   if (FState != osInactive)
      result         = _Bool_Ret[FState >= osOpened];
   else if (FDoOpen != NULL)
   {
      
      FState         = osOpening;
      boolNext       = true;
      FCloseThreadID = lwThread;
   }
   Unlock();

   // 判断是否继续
   if (boolNext)
   {
      // 执行打开, 若成功则添加连接请求
      boolNext = false;
      result   = (FObjOpen->*FDoOpen)(AParam);

      // 更改状态
      Lock();
      if (FState != osOpening)
         boolNext       = true;
      else if (result == orSuccess)
      {
         FState         = osOpened;
         FCloseThreadID = 0;
      }
      else
         FState         = osInactive;
      Unlock();

      // 判断是否需要关闭
      if (boolNext)
      {
         // 执行关闭
         if (result == orSuccess)
         {
            DoClose(true);
            result = orFailure;
         }

         // 更改状态(不需要加锁)
         FState = osInactive;
      }
   }

   // 返回结果
   return result;
}

// 关闭
void TKYObjState::Close(bool ANeedWait)
{
   // 检查状态
   if (FState == osInactive)
      return;

   // 初始化
   Longword lwThread = GetCurrentThreadId();
   bool     boolNext = false;
   bool     boolWait = false;

   // 更改状态
   Lock();
   if (FState >= osOpened)
   {
      FState         = osClosing;
      boolNext       = true;
      FCloseThreadID = lwThread;
   }
   else if (FState == osOpening)
   {
      FState         = osClosing;
      boolWait       = ANeedWait && (lwThread != FCloseThreadID);
   }
   else if (FState == osClosing)
      boolWait       = ANeedWait && (lwThread != FCloseThreadID);
   Unlock();

   // 判断是否继续
   if (boolNext)
   {
      // 执行关闭
      DoClose(true);

      // 更改状态(不需要加锁)
      FState = osInactive;
   }
   else if (boolWait)   // 等待 Close 结束
      while (FState == osClosing)
         Sleep(8);
}

// 设置已关闭(不执行 DoClose 回调)
void TKYObjState::SetClosed()
{
   // 初始化
   Longword lwThread = GetCurrentThreadId();
   bool     boolNext = false;

   // 更改状态
   Lock();
   if (FState >= osOpened)
   {
      FState         = osClosing;
      boolNext       = true;
      FCloseThreadID = lwThread;
   }
   else if (FState == osOpening)
      FState         = osClosing;
   Unlock();

   // 判断是否继续
   if (boolNext)
   {
      // 执行关闭
      DoClose(false);

      // 更改状态(不需要加锁)
      FState = osInactive;
   }
}

// 登录
int TKYObjState::Login(void* AParam)
{
   // 初始化
   int  result    = orFailure;
   bool boolNext  = false;

   // 更改状态
   Lock();
   if (FState != osOpened)
      result   = _Bool_Ret[FState >= osLogged];
   else if (FDoLogin != NULL)
   {
      FState   = osLogging;
      boolNext = true;
      InterlockedIncrement(&FRefCount);
   }
   Unlock();

   // 判断是否继续
   if (boolNext)
   {
      // 执行登录
      boolNext = false;
      result   = (FObjLogin->*FDoLogin)(AParam);

      // 更改状态
      Lock();
      if (FState != osLogging)
         boolNext = true;
      else if (result == orSuccess)
         FState   = osLogged;
      else
         FState   = osOpened;
      Unlock();

      // 判断是否需要登出
      if (boolNext)
      {
         // 执行登出
         if (result == orSuccess)
         {
            DoLogout();
            result = orFailure;
         }

         // 更改状态
         Lock();
         if (FState == osLogouting)
            FState = osOpened;
         Unlock();
      }

      // 引用计数减 1
      DecRefCount();
   }

   // 返回结果
   return result;
}

// 登出
void TKYObjState::Logout()
{
   // 初始化
   bool boolNext  = false;

   // 更改状态
   Lock();
   if (FState == osLogged)
   {
      FState   = osLogouting;
      boolNext = true;
      InterlockedIncrement(&FRefCount);
   }
   else if (FState == osLogging)
      FState   = osLogouting;
   Unlock();

   // 判断是否继续
   if (boolNext)
   {
      // 执行登出
      DoLogout();

      // 更改状态
      Lock();
      if (FState == osLogouting)
         FState = osOpened;
      Unlock();

      // 引用计数减 1
      DecRefCount();
   }
}

}

对象状态及示例代码(ObjState.rar)下载如下:
https://pan.baidu.com/s/1eTWTYD0#list/path=%2Fshares%2Fsources%2F_open

================================================================================
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值