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

  • 相关阅读:
    垂直搜索引擎蜘蛛
    利用Lucene.net搜索引擎进行多条件搜索的做法
    收缩数据库日志文件
    页头加上<!DOCTYPE html PUBLIC "//W3C//>后 js不符合w3c标准 对联不滚动
    winfrom中使用cache
    Vista与XP局域网文件共享设置方法
    如何快速高效的群发Email
    StringTemplate学习笔记(转载)
    清除sql 日志文件
    利用 Sandcastle 编写软件 SDK 文档
  • 原文地址:https://www.cnblogs.com/lancelod/p/4245769.html
Copyright © 2020-2023  润新知