首页 > 代码库 > [C++] 一个能够定时自毁的类的实现

[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的支持.

 

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