当前位置: 首页 > 科技观察

Linux:请允许我在后台安静运行

时间:2023-03-12 13:49:36 科技观察

前言经常在linux下玩的开发者肯定会遇到进程调度的需求。在windows下点最小化做其他的就OK了,然后在WhatshouldIdounderlinux?可能有朋友会说,再开一个终端窗口不就好了吗?但是打开很多窗口进行管理会很不方便。还有点x或者长时间不操作,远程终端断开,进程停止,再打开就折腾了。今天介绍几个命令,帮助大家系统梳理一下linux的进程调度,附上自己的一些经验和坑。名词在这之前,我们必须(当然不是必须的,但了解原理有利于理解和解决错误)了解几个名词。进程组进程组是一个或多个进程的集合。进程组方便了对多个进程的控制。在进程数量较多的情况下,向进程组发送信号即可。它的ID由其leader进程的进程ID决定。leader进程创建进程组,但不决定进程组的生存时间。只要进程组中有一个进程,这个进程就存在,不管leader进程是否已经终止。会话是一个或多个进程组的集合,从用户登录终端开始,到用户注销结束。顾名思义,它指的是用户与系统进行一次对话的全过程。会话由控制进程(建立到终端的连接的引导进程)、前台进程组和任何后台进程组组成。一个会话只能有一个控制终端,通常是终端设备或伪终端设备登录其中,控制终端上产生的输入和信号将被发送到该会话的前台进程组中的所有进程。控制终端每当我们使用终端工具打开本地或远程shell时,我们打开一个控制终端,通过ps命令可以看到命令为ttyn的进程是它对应的进程,它对应的是linux/dev/目录下的一个文件。作业作业的概念类似于进程组。它也由一个或多个进程组成。它分为前台作业和后台作业。一个会话将有一个前台作业和多个后台作业。与进程组不同,进程派生的子进程不属于该作业。类比上面的概念可以类比一次QQ聊天的全过程。控制端是QQ软件。关闭此软件意味着聊天结束。聊天过程中发送的每条消息都是一个进程,一个作业或者进程组就是我们正在谈论的某个事物,它由许多相互消息组成。会话是指从聊天开始到聊天结束的整个过程,我们可能会聊很多事情。它们之间的关联图如下:后台执行我们每次在终端窗口执行命令,进程都会一直占用终端,直到进程结束。这段时间我们在终端的输入是没有用的。而且,当终端窗口关闭或者网络连接失败时,如果再次打开终端,会发现进程已经中断了。这是因为当用户注销或网络断开时,会向会话所属的子进程发送SIGHUP信号,而对这个SIGHUP的默认处理方式是终止接收到该信号的进程。因此,如果程序中没有捕捉到信号,当终端关闭时,session所属的进程就会退出。我们要达到后台执行的目的,其实就是要完成以下两个目标:让进程放弃前台终端,让我们继续通过终端与系统进行交互。使进程不再受终端关闭的影响,即终端关闭后系统不再向进程发送SIGHUP信号或即使发送信号程序也不会退出。下面的命令就是围绕这两个目标实现的。&是我们最常遇到的符号&。附加在命令上可以使进程在后台执行而不占用前台界面。它实际上是在session中启动了一个后台job,后面会讲到job的运行。但是我们会发现,如果此时关闭了终端,进程还是会退出。这是因为&符号只是让进程放弃前台终端的功能,并不能阻止进程受到SIGHUP信号的影响。nohupnohup应该是我们常用的另一个命令。它的作用正如它的字面意思,使进程不受SIGHUP信号的影响。但是我们使用nohupphptest.php之后会发现进程会一直占用前台终端,但是即使关闭终端或者断开连接,程序依然会执行。另外我们会发现在当前文件夹File下多了一个名字为nohup.out。这是因为nohup的作用只是让进程不受SIGHUP信号的影响,不会放弃前台终端,同时还会在命令执行目录下创建nohup.out存放进程的输出。如果进程不需要输出,并且不想让nohup创建文件,则可以重定向标准输出和标准错误。我们经常将nohup和&一起使用。执行命令如下:nohupcommand>/dev/null2>&1&这样就可以安心等待处理结果了。setsidSetsid是另一个允许进程在后台执行的命令。它的作用是让进程开启一个新的会话并运行进程。使用方法是setsid命令。根据上面的概念,我们知道终端关闭后进程退出是因为sessionleader进程给进程发送了一个SIGHUP信号,setsid功能强大,它直接开启一个新的session来执行命令,那么终端状态为原来的session将不再这个进程不会受到影响。当使用setsid和nohup...&命令运行进程时,我们使用pstree查看进程树的状态。nohupphptest.php&我是用ssh远程登录本机,所以test.php进程挂在了sshd进程下。一般情况下,一旦sshd进程结束,test.php也不会幸免。setsidphptest.php使用setsid后,test.php进程已经和sshd进程处于同一级别,属于init进程的子进程。但是setsid并没有给进程分配输出终端,所以进程还是会输出到当前终端。setsid的陷阱另外,setsid有个小坑:在终端直接使用setsid命令运行进程时,不会影响终端前台,命令会在后台静默运行。在shell脚本中,我们会发现运行setsid的进程会被阻塞,直到命令进程执行结束。这是因为setsid是进程leader时会fork()一个进程,但不会wait()它的子进程,而是立即退出,所以在终端直接使用setsid时,setsid是进程leader不占用终端界面。在shell脚本中,setsid不是进程领导者,它不会fork()一个子进程,但是bash会fork()一个子进程,而bash会wait()这个子进程,所以它的表现就像setsidinwait()作为子进程。要解决这个问题,有两种方法:使用上面介绍的&符号强制setsid在后台执行。使用。或从终端执行setsid的source命令;除了上述命令外,还有screen、tmux等对话工具。它们都有自己的一套规格,并且相对复杂。掌握本文的命令,足以让你驰骋linux进程控制上来。当然想学习新知识的可以自己查询学习,应该比基本命令更容易上手。job命令使用上述后台执行命令时,可能会出现一些小情况:我们放在后台的进程执行时间太长,忘记使用nohup命令,那么一旦终端断开,该过程需要重新执行。我们直接启动某个进程,想在不打断进程的情况下让它从前台终端出来;这些都涉及到今天的第二个模块——工作;我们在终端中运行的命令可以理解为一个作业,有的作业占用前台终端,有的作业在后台默默执行。以下命令用于安排这些作业。jobjobs是作业的基本命令。可用于查看正在运行的作业的信息。其输出如下:jobs1-Runningphptest.php&2+Stoppedphptest.php[]前面的数字是作业ID,也就是我们后面要操作的作业ID,后面是作业状态和命令。严格来说,ctrl+zctrl+z不是作业命令。它只是向当前进程发送一个SIGSTOP信号,提示进程进入停止状态。在这个状态下,进程状态会被系统保存,进程会被放入jobQueue,并yield进程终端。使用它,我们可以挂起占用终端的进程而不停止它,允许我们使用终端命令来操作这个进程。bgbg是背景的缩写。顾名思义,bg%id将作业放入后台进程中执行。结合ctrl+z和bg命令,我们就可以解决上面提出的第一个问题,将正在占用终端的进程放到后台,不间断。fgfg与bg相反,用来将作业放到前台执行。disowndisown用于将作业从作业列表中移除,即使它不属于会话,这样终端关闭后,不会向该作业发送SIGHUP信号,防止终端影响进程。使用disown我们可以解决上面提出的第二个问题,而不用重新执行一个没有使用nohup命令的进程不受终端关闭的影响。上面介绍的daemon进程是一些临时进程的处理。进程后台运行的最后一个方法就是把进程变成守护进程。守护进程(daemon)是一个生命周期很长的进程。它通常在系统启动时启动,在系统关闭时停止。没有控制终端,也没有输出。我们的server、fpm等进程都是以守护进程的形式存在的。创建daemon进程,步骤如下:fork子进程,退出父进程,子进程作为孤儿进程被init进程收养;使用setsid,开启一个新的session,进程成为sessionleader,正式脱离终端控制;设置信号处理(尤其是子进程退出处理);options:使用chdir改变进程工作目录,一般为根目录,防止无法挂载的文件系统被占用;使用umask重置文件权限掩码,不再继承父进程的文件权限设置;关闭父进程打开的文件描述符;下面的代码是在php中创建守护进程的伪代码:$pid=pcntl_fork();if($pid>0){exit;//父进程直接退出}elseif($pid<0){throw_error();//进程创建失败}posix_setsid();//setsid成为会话领导进程chdir($dir);//切换目录umask(0);//重置文件权限maskclose_fd();//关闭文件描述符父进程的pcntl_signal($signal,$func);//注册信号处理函数while(true){do_job();//处理进程任务pcntl_signal_dispatch();//分发信号处理}开发人员,进程调度是常用的功能。希望看完这篇文章的同学能够有所收获。半个多月没写博客了。最近一直在鼓捣重构代码。经常纠结于一点,不知不觉就要加班。而这是一份无法准确衡量工作量和目标的工作。优化永无止境。不过由于要考虑更多的是代码的抽象、效率和扩展,对自己也是一个挑战,所以乐在其中~最近可能会考虑写一个daemon进程和cron进程调度器,嗯,我希望对我来说算作工作量,哈哈~想写的太多了,只怪自己不够坚强。..