关于应用程序的重启

在我们平时用电脑的过程中,最不想遇到的事情就是机器重启了,它造成的除了等待之外还有惊悚,毕竟我们谁也不想让磁盘在自检过程中失败。但是应用程序重新启动也不是什么好事,本文就简单谈谈应用程序的重新启动。
电脑重启有两种方式,一种是冷重启,另一种是热重启,这两种有何区别,其实冷重启是硬件的复位,而热重启硬件没有复位而只是指令的复位,实际上,在热重启过程中,硬件并没有任何感知,只是作为软件的cpu指令跳转到最最开始的位置,比如在x86平台就是0x
7c00的位置,并且回归到实模式,仅此而已,硬件电路该通则通,没有任何异常。但是冷重启就不一样了,冷重启是硬件的复位,举个例子就是当你按下重启键时,物理线路被切断,相关引脚的电平拉低,然后引 起一系列反应引起整个机器的复位,从而造成重启,可以看出这种重启是物理原因造成的,物理连线引起的,软件指令是被动执行重启行为的,不同于热重启,在热重启中,软件指令是主动执行重启行为的。
实际上,任何可以顺序执行的物件都可以重新启动,这里的意义很简单,所谓重启必然有一个启动,只有启动的东西才可以重新启动,而启动意味着开始,大家都知道冯氏的指令都是顺序执行的,所以不光是机器,所有冯氏机器里面的执行绪都可以被重启,当然也都有冷重启和热重启两种方式。本质上讲,整台冯氏机器就是一 个执行绪,可以叫做机器进程(参见《操作系统》一书,老外写的),这个意义上机器进程和我们的应用程序进程没有区别,只不过应用程序进程的层次比机器进程的层次更高。
我们看一下应用程序怎么重启,不知道大家有没有用过迅雷和eclipse,当遇到一些问题的时候,会弹出一个对话框说程序要重启,然后我们点确定,原来的 进程退出,新的进程起来了,这一切看似简单,仔细考虑一下就会发现并不容易实现,因为在旧进程退出和新进程启动的时间间隔里,这个进程实际上没有任何信息在系统里面,除非有一个第三方进程一直在监视这个进程,当检测到该进程退出并且要求重启时,立马再重新启动一个相同的进程,如果没有这个第三方管理进程, 重启看来是很难实现的。可是真的就是很难实现吗?
我们回想一下冯氏机器的特点就会知道,只要让执行指令回到原点就可以了,这种重新启动就是热重启,那么怎么实现指令的回归呢?在linux中,我们可以用 exec来实现,exec谁呢?当然是exec自己了,比如当前在执行“test”,那么就在test内部的异常处理中要重启当前进程的地方调用 execX("test",...)就可以了,这就是热重启,也就是软件指令主动的重启,一切大环境,大容器都没有变,只不过容器里面的东西变了而已,在 linux中可以看出,在执行完exec重启该进程后,进程的pid并没有变化,包括信号的阻塞掩码也没有变化,你要想让之变化,那么你就必须手工设置, 在windows中,好像没有什么办法可以实现上述的热重启操作,重启操作过后,一切都变了,不光人非,物也非了(linux中可以做到物是人非)。
如果想实现冷重启,很简单,就是被动的执行就可以了,这就需要一个管理进程来操作重启行为了,比如该管理进程先杀死原始进程,等待一切干净以后,马上再启动一个就是了,这里的管理进程相当于机器重启过程中的硬件的作用,是一个主动发号指令的实体。必须要明白的是,重启的种类有两种,如果容器不变只是内容变 化了,那么就是热重启,如果连容器都变了,那么就是冷重启,抛开冷热不谈,重启的本质是指令的重新执行,是一种指令的回归。理论扯完了,那么就看一下代码吧,我这里有一个进程重启的代码,我们知道在linux中进程指的不仅仅是可执行映像的动态行为,还可以是fork后的执行绪,我这里给出的代码就是重新 启动fork后的子进程的代码:

#include

 

#include

 

void restart(int sig) 

    waitpid(-1, NULL, 0); 

    if(符合重启条件) 

        execl("./test", "test", NULL); 

int main() 

    sigset_t mask;    //这个和以下3行是为了解除屏蔽SIGCHLD信号,因为在父进程收到SIGCHLD信号后,就会阻塞屏蔽该信号,因此即使你exec了自己,那么 SIGCHLD还将存在于阻塞集合当中,必须去除之才可以持续接受SIGCHLD信号

    sigemptyset(&mask); 

        sigaddset(&mask,SIGCHLD); 

        sigprocmask(SIG_UNBLOCK,&mask,NULL); 

    signal(SIGCHLD, restart); 

    if(fork() == 0) 

    { 

*    ...//做自己的事情,实现进程逻辑

    } 

    ...//无限等待

}  

该代码被编译为test可执行程序,当你执行的时候,*会执行,当它遇到问题退出的时候,在restart信号处理函数中会被重启,在遇到问题 fork子进程退出的时候,发送SIGCHLD信号给父亲,那么restart处理函数就会被执行,进而重启。那么如何改造之后将上述代码实现为热启动呢?很简单,就是将fork去掉,将restart作为信号处理函数提供改为作为异常处理函数提供,我们可以看到,在fork+信号处理实现的冷重启中, 进程的pid发生了变化,而在直接exec实现的热重启中,pid没有发生变化,因此如果想持续根据pid跟踪一个进程,那么最好在遇到问题的时候用热重 启,不幸的时,这在windows下很难实现(也许是我还很嫩,还没有学会),在windows下必然的造成了pid的改变,即使你直接用exec(参见 前一篇文章)。当然你完全在上述代码的fork子进程中执行exec,效果一样。

在热重启的时候要注意一定要做善后工作,也就是说一定要释放掉先前的资源,不光执行流要复位,资源也要复位,正如在linux执行reboot的时候,一 定要让各种硬件也复位一样,对于机器的热重启,资源就是各种硬件,对于进程,资源就是如文件描述符之类的东西。

原文链接: https://blog.csdn.net/dog250/article/details/5302812

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    关于应用程序的重启

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/410701

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月26日 下午12:10
下一篇 2023年4月26日 下午12:10

相关推荐