【Linux、C】实现进程的心跳机制类

把进程的信息结构体存到共享内存中,不断更新最后一次的心跳时间。

注意点:由于每个进程之间会争夺共享内存的使用权,所以需要给共享资源加锁(框架中有CSEM类),该类实现好后,也能加到框架中,能大大节省开发时间

#include "_public.h"

#define MAXNUMP_ 1000   // 最大的进程数量
#define SHMKEYP_ 0x5059 // 共享内存的key

// 进程心跳信息的结构体
struct st_pinfo
{
    int pid;        // 进程id
    char pname[51]; // 进程名称,可以为空
    int timeout;    // 超时时间,单位:秒
    time_t atime;   // 最后一次心跳的时间,用整数
};

class PActive
{
public:
    PActive();
    ~PActive();

public:
    bool AddPInfo(const int timeout, const char *pname); // 把当前进程的心跳信息加入共享内存中
    bool UptATime();                                     // 更新共享内存中当前进程的心跳时间
private:
    CSEM m_sem;
    int m_shmid;
    int m_pos;
    struct st_pinfo *m_shm;
};

PActive::PActive()
{
    m_pos = -1;
    m_shm = nullptr;
    m_shmid = -1;
}

// 把当前进程的心跳信息加入共享内存进程组中。
bool CPActive::AddPInfo(const int timeout, const char *pname, CLogFile *logfile)
{
    if (m_pos != -1)
        return true;

    if (m_sem.init(SEMKEYP) == false) // 初始化信号量。
    {
        if (logfile != 0)
            logfile->Write("创建/获取信号量(%x)失败。\n", SEMKEYP);
        else
            printf("创建/获取信号量(%x)失败。\n", SEMKEYP);

        return false;
    }

    // 创建/获取共享内存,键值为SHMKEYP,大小为MAXNUMP个st_procinfo结构体的大小。
    if ((m_shmid = shmget((key_t)SHMKEYP, MAXNUMP * sizeof(struct st_procinfo), 0666 | IPC_CREAT)) == -1)
    {
        if (logfile != 0)
            logfile->Write("创建/获取共享内存(%x)失败。\n", SHMKEYP);
        else
            printf("创建/获取共享内存(%x)失败。\n", SHMKEYP);

        return false;
    }

    // 将共享内存连接到当前进程的地址空间。
    m_shm = (struct st_procinfo *)shmat(m_shmid, 0, 0);

    struct st_procinfo stprocinfo; // 当前进程心跳信息的结构体。
    memset(&stprocinfo, 0, sizeof(stprocinfo));

    stprocinfo.pid = getpid();                                      // 当前进程号。
    stprocinfo.timeout = timeout;                                   // 超时时间。
    stprocinfo.atime = time(0);                                     // 当前时间。
    STRNCPY(stprocinfo.pname, sizeof(stprocinfo.pname), pname, 50); // 进程名。

    // 进程id是循环使用的,如果曾经有一个进程异常退出,没有清理自己的心跳信息,
    // 它的进程信息将残留在共享内存中,不巧的是,当前进程重用了上述进程的id,
    // 这样就会在共享内存中存在两个进程id相同的记录,守护进程检查到残留进程的
    // 心跳时,会向进程id发送退出信号,这个信号将误杀当前进程。

    // 如果共享内存中存在当前进程编号,一定是其它进程残留的数据,当前进程就重用该位置。
    for (int i = 0; i < MAXNUMP; i++)
    {
        if ((m_shm + i)->pid == stprocinfo.pid)
        {
            m_pos = i;
            break;
        }
    }

    m_sem.P(); // 给共享内存上锁。

    if (m_pos == -1)
    {
        // 如果m_pos==-1,共享内存的进程组中不存在当前进程编号,找一个空位置。
        for (int i = 0; i < MAXNUMP; i++)
            if ((m_shm + i)->pid == 0)
            {
                m_pos = i;
                break;
            }
    }

    if (m_pos == -1)
    {
        if (logfile != 0)
            logfile->Write("共享内存空间已用完。\n");
        else
            printf("共享内存空间已用完。\n");

        m_sem.V(); // 解锁。

        return false;
    }

    // 把当前进程的心跳信息存入共享内存的进程组中。
    memcpy(m_shm + m_pos, &stprocinfo, sizeof(struct st_procinfo));

    m_sem.V(); // 解锁。

    return true;
}

// 更新共享内存进程组中当前进程的心跳时间。
bool CPActive::UptATime()
{
    if (m_pos == -1)
        return false;

    (m_shm + m_pos)->atime = time(0);

    return true;
}

CPActive::~CPActive()
{
    // 把当前进程从共享内存的进程组中移去。
    if (m_pos != -1)
        memset(m_shm + m_pos, 0, sizeof(struct st_procinfo));

    // 把共享内存从当前进程中分离。
    if (m_shm != 0)
        shmdt(m_shm);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
        return -1;
    PActive Active;
    Active.AddPInfo(20, argv[1]);
    while (1)
    {
        Active.UptATime();
        sleep(1);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值