title: linux进程心跳
date: 2024-05-20 12:00:00
categories:
- linux
- 进程心跳
tags: 进程心跳
进程的心跳
进程心跳是一种周期性发送信号的技术,用于确认系统或者组件是否处于正常运行状态。通常,心跳信号由一个程序或者进程定期发送给另一个程序或者进程,接收方通过监测心跳信号的到达情况来判断发送方的状态。在C++中,心跳机制可以通过定时器、线程、网络套接字等方式实现,具体实现方式取决于应用的需求和环境
进程心跳就像是一个定时发出的“我还活着”的信号。想象一下,如果你有一个机器人朋友,在另一个房间工作,你不能看到它。为了确保它还在正常工作,你让它每隔一段时间就对你喊一声“我还好”。只要你听到它的声音,你就知道它还在那里工作。如果你突然听不到它的声音了,那可能意味着它遇到了问题,需要你去检查一下。
在计算机程序中,这个“喊声”就是心跳信号。一个程序会定期发送这个信号给另一个程序,告诉它“我还在运行”。如果心跳信号停了,接收信号的程序就知道发送信号的程序可能出了问题,需要采取一些措施。这个机制帮助程序员确保系统的稳定性和可靠性。简单来说,进程心跳就是程序之间用来检查对方是否还在正常运行的一种方法。
例子:
这段代码通过使用共享内存来实现多进程间的进程心跳,在这个例子中的“喊声”就是进程的当前时间,每隔一段时间更新一次atime这个参数,当每次超过超时时间后这个参数仍没有改变就知道该进程出现了问题。
#include "_public.h"
using namespace idc;//进程心跳的结构体
struct stprocinfo
{int pid=0; //进程idchar pname[51]={0}; //进程名int timeout = 0; //超时时间time_t atime = 0; //最后一次心跳的时间(最后一次“发送信号”)stprocinfo() = default; //启用默认构造stprocinfo(const int in_pid,const std::string& in_pname,const int in_timeout,const time_t in_atime):pid(in_pid),timeout(in_timeout),atime(in_atime){strncpy(pname,in_pname.c_str(),50);}
};int m_shmid = -1; //共享内存的id
struct stprocinfo* m_shm = nullptr; //指向共享内存的地址空间
int m_pos = -1; //当前进程在数组中的下标void EXIT(int sig); //退出信号的处理函数int main()
{ //处理程序的退出信号signal(SIGINT,EXIT);signal(SIGTERM,EXIT);//创建/获取共享内存if(m_shmid = shmget((key_t)0x5095,1000*sizeof(struct stprocinfo),0666|IPC_CREAT)==-1){printf("创建/获取共享内存(%d)失败. \n",0x5095);return -1;}//连接共享内存到当前进程的地址空间if((m_shm = (struct stprocinfo*)shmat(m_shmid,0,0))==(void*)-1){printf("连接到当前进程地址失败. \n");return -1;}//将共享内存中的全部进程信息显示出来用于调试for (int i = 0; i < 1000; i++){if(m_shm[i].pid!=0)//m_shm+i{printf("i=%d,pid=%d,pname=%s,timeout=%d,atime=%d\n",i,m_shm[i].pid,m_shm[i].pname,m_shm[i].timeout,m_shm[i].atime);}}//将当前进程的信息填充到结构体//procinfo.atime = time(0); //获取当前系统时间作为最后一次心跳时间(1970-1-1以来的秒数)struct stprocinfo procinfo(getpid(),"server1",30,time(0));//查找位置并操作内存,防止多个进程同时找到用一个位置这种情况,对共享内存加锁(信号量)csemp semlock; //给共享内存加锁的信号量if(semlock.init(0x5095)==false)//初始化信号量{printf("创建信号量%x失败.\n",0x5095);EXIT(-1);}semlock.wait();//加锁// 进程id是循环使用的,如果曾经有一个进程异常退出(fragment fault/kill-9),没有清理自己的心跳信息,// 它的进程信息将残留在共享内存中,不巧的是,如果当前进程重用了它的id,// 所以,如果共享内存中已存在当前进程编号,一定是其它进程残留的信息,当前进程应该重用这个位置。for(int i = 0;i<1000;i++){//m_shm+i也可以,因为m_shm是stprocinfo类型,所以+i表示加i个stprocinfo大小的位置if(m_shm[i].pid == procinfo.pid)//如果当前进程id在内存中已存在{m_pos = i; //设置当前进程位置(标记这个位置)即重用这个位置printf("Find the old position %d. \n");break;}}if(m_pos == -1){//在共享内存中寻找空位置并将进程的结构体保存到共享内存中for(int i = 0;i<1000;i++){if(m_shm[i].pid == 0) //如果pid为空,也就是当前位置为空位置{m_pos = i; //设置当前进程位置(标记这个位置)printf("Find a new position %d. \n",i);break;}}}//若m_pos==-1表示没有找到空位置,共享内存空间已用完if(m_pos == -1){semlock.post(); //解锁printf("The shm is full.\n");EXIT(-1);}//把当前进程的结构体保存到共享内存中//memcpy(m_shm + m_pos,&procinfo,sizeof(struct st_procinfo)); memcpy(&m_shm[m_pos],&procinfo,sizeof(struct st_procinfo));semlock.post(); //解锁while(true){std::cout<<"服务程序正在运行中...\n";//每隔这么多秒更新一次心跳(发送一次信号),不能大于超时timeout时间sleep(25);//更新进程的心跳信息m_shm[m_pos].atime=time(0);sleep(25);m_shm[m_pos].atime=time(0);}return 0;
}void EXIT(int sig)
{printf("sig=%d\n",sig);//从共享内存中删除当前进程的心跳信息if(m_pos !=-1)memset(&m_shm[m_pos],0,sizeof(struct stprocinfo));//把共享内存从当前进程分离if(m_shm != 0 )shmdt(&m_shmid);exit(0);//退出程序
}