试想一下, 有没有这种需求:

对于每一个新的对象, 我们希望它能够在一定时间后自动销毁, 前提是我们没有在这段时间内给它发出重置信号.

这种需求其实是有的, 比如在电影里, 主角知道了一个反派不希望被揭露的秘密, 同时需要保住自己的性命, 那么就可以构造这样一个对象, 如果24小时内主角不给这个对象发送重置的信号, 它就会将这个秘密公之于众. 再比如, 在网络应用场景里, 我们希望每一个客户端能够定时给我们发送心跳包, 如果长时间不发送的话, 我们就剔除这个客户.

在之前的文章里, 我尝试使用了WIN32的Timer, 但是发现这种做法非常繁琐且容易出错, 你需要给每个对象绑定一个Timer, 同时需要在Timer到期时处理对象, 并且重置Timer的API和设置Timer的API是同一个, 稍有不慎就会搞砸.

现在, 我想出了一种相对简单的实现方式, 虽然精度不是非常理想, 但对于一般应用而言, 足矣.


我们构造一个类, 它有一些私有的数据, 这些可以自定义, 但有一些API是必须的:

class Client
{
private:
// ...Data or something
int32_t m_life;
int32_t m_max_life;
DWORD delete_thread_id;
HANDLE count_thread_handle;
public:
Client(int32_t, DWORD);
void reset(void);
static WIN32API DWORD countDownEntry(void *);
DWORD countDown(void);
// ...De-cons...
}

1. 构造函数:

Client:Client(int32_t life, DWORD thread_id)
{
m_max_life = m_life = life;
delete_thread_id = thread_id;
count_thread_handle = CreateThread(..., ..., Client::countDownEntry, this);
}

第二个参数是用来销毁对象的线程ID, 这样设计是考虑到对象有可能保存在一个堆, 如果我们简单地调用析构函数, 那么对象本身所占据的空间就无法被释放了, 所以我们通知这么一个线程来完成所有的析构操作.

注意到我们使用的是countDownEntry()而不是countDown(), 因为CreateThread不接受一个非静态的成员函数作为函数入口(无法确认地址).

2. reset()方法, 这方法需要先挂起倒计时的线程, 主要是防止同时访问同一个内存的情况出现:

void Client::reset(void)
{
SuspendThread(count_thread_handle);
m_life = m_max_life;
ResumeThread(count_thread_handle);
}

3. countDownEntry()方法为何是static的? 很简单, 我们需要在构造函数里使用它来初始化倒计时线程, 而它的实现非常简单, 我们在构造函数里把this指针传递给这个静态方法, 并在静态方法里重新获取这个this代表的对象, 调用这个对象的倒计时函数即可:

static WIN32API DWORD Client::countDownEntry(void *pM)
{
Client *c = (Client *) pM;
return c->countDown();
}

4. 而countDown()方法更加简单, 使用Sleep函数来计时即可, 每计一秒就将life减1:

DWORD Client::countDown()
{
while (m_life > )
{
Sleep();
m_life--;
}
PostThreadMessageA(delete_thread_id);
return ;
}

以上就是这样一个对象的设计思路, 原理比较简单, 也只是写了个大概, 同时需要windows.h的支持.

[C++] 一个能够定时自毁的类的实现的更多相关文章

  1. 3.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff。

    23.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff. 具体要求如下: (1)Person类中的属性有:姓名name(String类型) ...

  2. classmethod一个用处是创建可选类构造器

    Definition and Introduction通常来说, descriptor 是一种绑定着特殊行为属性的对象, 在访问它时行为被descriptor协议定义的方法所重载.这些方法是__get ...

  3. 一天一个Java基础——对象和类

    1.在Java中你所做的全部工作就是定义类,产生那些类的对象,以及发送消息给这些对象 2.可以在类中设置两种类型的元素:字段(也被称作数据成员)和方法(也被称作成员函数) 3.字段可以是任何类型的对象 ...

  4. 一个漂亮的php验证码类

    一个漂亮的php验证码类(分享)   作者: 字体:[增加 减小] 类型:转载 下面小编就为大家分享一个漂亮的php验证码类.需要的朋友可以过来参考下   直接上代码: 复制代码 代码如下: //验证 ...

  5. 设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”。。。

    设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”,则抛出一个异常信息“This is a XYZ”,如果从命令行输入 ABC,则没有抛出异常.(只有 ...

  6. CSS一个元素同时使用多个类选择器(class selector)

    CSS类选择器参考手册 一个元素同时使用多个类选择器 CSS中类选择器用点号表示.实际项目中一个div元素为了能被多个样式表匹配到(样式复用),通常div的class中由好几段组成,如<div ...

  7. 定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x和虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Complex(int i,int j) 显示复数的方法:showComp()将其显示为如: 5+8i或5-8i 的形式。 求两个复数的和的方法:(参数是两个复数类对象,返回值是复数类对象)public Complex addComp(Compl

    因标题框有限,题目未显示完整,以下再放一份: 定义一个复数(z=x+iy)类Complex,包含: 两个属性:实部x和虚部y 默认构造函数 Complex(),设置x=0,y=0 构造函数:Compl ...

  8. Eclipse里选中一个变量后,这个类里的该变量不变色了?

    Eclipse里选一个变量后,这个类里的该变量不变色了. 1.使用“Alt+Shift+O”对该提示功能的开/关切换 2.可以在以下设置选中后的文本提示颜色  window--> Prefere ...

  9. String、StringBuffer和StringBuilder,定义一个自己的StringBuilder的类

    String Java中的字符串值属于String类,虽然有其它方法表示字符串(如字符数组),但Java一般使用String类作为字符串的标准格式,Java编译器把字符串值作为String对象; St ...

随机推荐

  1. OAF 动态创建组件以及动态绑定属性

    在开发中,我们遇到以下一个需求. 一个表格左侧有5列是固定存在的,右侧有N列是动态生成的,并且该N列中第一列可输入,第二列是不可编辑的,但是是数字,如果小于0,那么就要显示为红色,重点标识出来. 首先 ...

  2. spark collect获取所有元素

    from pyspark import SparkConf, SparkContext conf = SparkConf().setMaster("local").setAppNa ...

  3. PHP:第一章——PHP中的数组运算符和类运算符

    数组运算符: $a+$b;//$a和$b的联合 $a == $b;//比较$a与$b的值相同为true; $a === $b;//如果$a与$b的值与顺讯完全相同为true; $a !=$b;//如果 ...

  4. HDU 1710 二叉树遍历

    首先.先序遍历是先访问根节点.然后左节点 然后右节点.从根节点开始 直到它的子节点没有左节点才开始回溯访问上一个节点的右节点.同理.中序遍历 先访问左节点 然后是父节点 然后是右节点.从根节点开始 直 ...

  5. html frameset的介绍

    frameset 元素可以定义一个框架集.它被用来组织多个窗口(框架).每个框架存有独立的文档. 属性 ①border 设置框架的边框粗细. ②bordercolor 设置框架的边框颜色. ③fram ...

  6. jenkins的流水线pipeline+项目实验php

    声明:实验环境使用Jenkins的应用与搭建的环境 新建一个流水线 pipeline脚本语法架构 node('slave节点名'){ def 变量 #def可以进行变量声明 stage('阶段名A') ...

  7. Oracle 等待事件 db file sequential read

    db file sequential read-数据文件顺序读取 等待事件: "db file sequential read" Reference Note (文档 ID 345 ...

  8. flashfxp 命令行

    以后更新软件时,尽量用bat命令行 http://www.flashfxp.com/forum/flashfxp/frequently-asked-questions-faq-/14748-comma ...

  9. Java虚拟机运行时数据区

    运行时数据区程序计数器Java虚拟机栈本地方法栈Java堆(GC堆)方法区运行时常量池 运行时数据区 Java虚拟机在运行Java程序时,会将它所管理的内存划分为若干个内存区域.这些数据区域有各自的用 ...

  10. Python 日志管理封装

    封装python中的logging方便日常使用 class Logger(object): level_mapping = { 'debug': logging.DEBUG, 'info': logg ...