[C++] 一个能够定时自毁的类的实现

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

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

这种需求其实是有的, 比如在电影里, 主角知道了一个反派不希望被揭露的秘密, 同时需要保住自己的性命, 那么就可以构造这样一个对象, 如果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 > 0)
    {
         Sleep(1000);
         m_life--;
    }
    PostThreadMessageA(delete_thread_id);
    return 0;
}

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

时间: 2024-10-11 22:53:21

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

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

1.在Java中你所做的全部工作就是定义类,产生那些类的对象,以及发送消息给这些对象 2.可以在类中设置两种类型的元素:字段(也被称作数据成员)和方法(也被称作成员函数) 3.字段可以是任何类型的对象,可以通过其引用与其进行通信:也可以是基本类型中的一种.如果字段是对某个对象的引用,那么必须初始化该引用,以便使其与一个实际的对象向关联(使用new来实现) 4.可以把两个类放在同一个文件中,但是文件中只能有一个类是公共的.此外,公共类必须与文件同名 1.1 构造方法构造对象 构造方法是一种特殊的方

需求:有一个猜数字小游戏,请写一个程序实现在测试类中只能使用5次,超过5次提示:游戏试玩结束,请付费。

package cn.idcast4; import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.Reader;import java.io.Writer;import java.util.Properties; /* * 需求:有一个猜数字小游戏,请写一个程序实现在测试类中只能使用5次, *

PHP实现的一个简单的数据库操作类

PHP实现的一个简单的数据库操作类 实现的功能: - 在实例化的时候能设置连接字符集 - 在实例化的时候能连接数据库 - 在实例化的时候能选择默认数据库 - 销毁对象时关闭数据库 代码如下: <?php // 数据库操作类MySQLDB class MySQLDB { // 声明属性 private $server; private $username; private $password; public $default_db; public $link; // 声明构造函数 public f

一个重构的js分页类

// JavaScript Document /**//** * js分页类 * @param iAbsolute 每页显示记录数 * @param sTableId 分页表格属性ID值,为String * @param sTBodyId 分页表格TBODY的属性ID值,为String,此项为要分页的主体内容 * @Version 1.0.0 * @author 辛现宝 2007-01-15 created * var __variable__; private * function __met

Functions类,一个Javascript的函数加法类,将两个函数加起来,顺序执行

以下是类的代码: 1 var Functions = { 2 oFunctions: null, 3 add: function (oFunc, oNewFunc) { 4 var oNew = function () { 5 oFunc(); 6 oNewFunc(); 7 }; 8 return oNew; 9 } 10 }; 以下是测试代码: 1 function one() { 2 alert(1); 3 } 4 5 function two() { 6 alert(2); 7 } 8

一个生成网页验证码的类 (mycome-validate)

一个小练习 可以通过 BufferedImage next() 返回一个内存图片 也可以通过String void next(OutputStream out) 写到一个输出流中,并返回验证码的值 jar包下载:http://files.cnblogs.com/mycome/mycome-validate.zip package validate; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; i

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

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

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

23.实现一个名为Person的类和它的子类Employee,Employee有两个子类Faculty 和Staff. 具体要求如下: (1)Person类中的属性有:姓名name(String类型),地址address(String类型), 电话号码telphone(String类型)和电子邮件地址email(String类型): (2)Employee类中的属性有:办公室office(String类型),工资wage(double 类型),受雇日期hiredate(String类型): (3

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

Definition and Introduction通常来说, descriptor 是一种绑定着特殊行为属性的对象, 在访问它时行为被descriptor协议定义的方法所重载.这些方法是__get__, __set__ 和__delete__. 如果对象定义了任一方法,这个对象就被叫做descriptor.访问对象的属性默认行为是get, set或delete对象字典中的属性.例如, a.x查找路径是从a.__dict__['x']开始,然后是type(a).__dict__['x'],并继