linux终端关闭时为什么会导致在其上启动的进程退出?

本文深入探讨了在Linux环境下,为何终端关闭时在终端上启动的程序也随之退出的现象。通过对进程管理和session机制的详细分析,揭示了SIGHUP信号在这一过程中的作用,并提供了几种避免进程随终端关闭而退出的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现象

经常在linux下开发的人应该都有这样的经验,就是在终端上启动的程序,在关闭终端时,这个程序的进程也被一起关闭了。看下面这个程序,为了使进程永远运行,在输出helloworld后,循环调用sleep:

这里写图片描述

直接关闭这个终端,在另一个终端上查找该进程,已经找不到了:

这个行为看起来似乎是理所当然的,也符合人的第一感觉:”在终端上启动的程序是属于终端的,所以当关闭终端时,这个终端里的一包裹进程都一起被解决掉了”。但这种说法是不能使一个会思考且充满好奇心的人信服的。

下面我们就从linux进程管理的细节来剖析其根本原因。

终端进程

linux系统是基于进程的,几乎每个命令都可以在相应的目录下找到它们的程序,执行一个命令相当于启动一个或多个程序,终端也不例外,在我centos下面终端对应一个bash程序(不同操作系统终端的bash程序可能不一样),它位于/usr/bin/下面:

这里写图片描述

每当打开一个终端都会启动一个bash进程,我这里启动了两个终端,可以看到有两个bash进程:

这里写图片描述

终端进程与启动进程的关系

linux系统里面所有的进程的关系可以看做一个树形结构,系统持续运行,进程的不断启动就是不断fork的过程(fork是linux系统api,作用是复制自己来生成子进程),从系统启动、初始化、登录终端、到执行命令都是生成子进程的过程:

这里写图片描述

init进程是所有进程的祖先,它的pid(进程id)为1,ppid(父进程id)也为1,因为它没有父进程,系统内的其他进程都是由它或者它的子进程fork而来。

我们在linux上作业的终端对应了一个bash进程,在其上运行的命令和程序都是bash的子进程,或由bash的子进程衍生。

用hw程序验证一下,可以看到hw进程的父进程正好是bash进程:

这里写图片描述

但这并不能解释为什么终端关闭了在上面运行的程序也跟着退出,因为在linux下,进程之间的关系并不像线程那样,当主线程退出时,子线程一起被强制退出。进程之间没有主次的区别,但有父子关系,而父子进程的运行是相对独立的,一方的退出不会导致另一方退出。

进程session-揭开真相

在linux下,一个session是由一组进程组构成的,每个进程组又由多个进程构成。

在一个bash上运行的程序都归属于一个session(除非特别处理),而这个bash就是这个session的leader。每个session又可以关联一个控制终端(Controlling Terminal)。

这里写图片描述

图片:

  1. hw进程的ppid=5933,说明父进程为第一个bash,这个bash的父进程为gnome-ternimal进程,gnome-ternimal是centos可视化界面的终端管理进程,每打开一个终端,它都会启动一个bash进程,而用户的命令也是直接由bash进程执行的。
  2. hw程序和第一个bash同属于一个session(sid=5933),这个sid等于bash的pid,所以第一个bash是这个session的leader。
  3. 图片中还显示了bash和hw进程拥有共同的终端设备pts/2,它是一种字符设备,不同于上面提到的gnome-ternimal进程。
  4. 当控制终端(对应gnome-ternimal)检测到终端设备断(对应pts/2)开连接时,会通知设备的控制进程,即发送SIGHUP信号给session leader(对应bash进程)。
  5. bash进程在收到SIGHUP后,将信号发给session下的所有进程,导致用户启动的进程退出。

下面通过strace命令来验证以上结论:

  1. 跟踪hw进程(命令意为跟踪pid为6367的进程上与signal有关的系统调用):

    strace -e trace=signal -p 6367

  2. 跟踪bash进程(命令意为跟踪pid为5933的进程上与signal有关的系统调用):

    strace -e trace=signal -p 5933

  3. 关闭启动hw程序的终端,观察strace输出.

hwd的strace如下,si_pid=5933说明是5933这个进程发了SIGHUP给它,也就是bash进程:

这里写图片描述

bash的strace略微复杂:

这里写图片描述

  1. kill(4294960929, SIGHUP)

    kill第一个参数是32位有符号整数,转换成int就是-6367,当参数为负时表示发送给这个数绝对值的进程组,即pgrp=6367的所有进程,在上面的图片中可以看到hw进程正好属于该进程组。

  2. kill(5933, SIGHUP)

    5933是自己的pid,bash在第一次收到SIGHUP时先把信号发给session内其他进程,然后再次发送SIGHUP命令给自己,将自己杀死,后面的si_pid=5933也证实了这一点。

如何让终端关闭时进程不退出

根据上面的结论,要使终端关闭时进程不退出,有以下几种情况:

  1. 用户进程拦截SIGHUP信号。
  2. 用户进程和bash进程不在一个session。

下面依次验证这两种情况

拦截SIGHUP

修改hw程序,忽略SIGHUP信号:

signal(SIGHUP, SIG_IGN);

执行hw程序,并查看进程,可以看到hw进程和父进程bash:

这里写图片描述

关闭终端,在另一个终端查看进程:

这里写图片描述

bash进程已经退出,但hw进程还在,符合预期!!而且hw进程的ppid变成了1,说明hw在父进程bash退出后变成孤儿进程被init进程收养。

新建session&setsid

为了使用户进程和bash不在同一个session,需要调用setsid方法,该方法的作用是新建一个新的session,并使自己成为leader。

// 先fork
int pid = fork();
if(pid > 0){
    // 父进程, 直接退出
    return 1;
}else if(pid == 0){
    // 子进程
    // 创建新的session
    setsid();
    //
    printf("Hello World!\n");
    printf("sleeping...\n");
    while(1){
        sleep(1);
    }
}

调用setsid前先fork,因为若不fork,hw作为进程组的leader,是不允许重建session的,原因留给读者自己思考。

编译并执行hw,查看进程:

这里写图片描述

可以看到,相比之前,有几个不同的地方:

  1. 程序启动完,返回终端,hw切换到后台运行。
  2. hw进程的父进程不再是bash,而是init进程。
  3. hw没有关联的终端设备(pts/2)。

关闭终端,看到bash已经消失,但对hw进程没有任何影响:

这里写图片描述

更简单的方法

  1. setsid命令,用setsid来启动程序,这样就不用修改任何代码也可以做到使启动的进程在新的session中,并且终端关闭时,进程不退出。

    setsid ./hw

  2. nohup命令,被nohup启动的程序会忽略SIGHUP信号。

    nohup ./hw

其他

命令行中&的作用:

./hw &

&的作用是使程序在后台运行,输入fg命令又可以使程序切换到前台。虽然在后台运行,但并不能保证进程在终端关闭时不退出。

总结

简而言之,终端在关闭时会发送SIGHUP给对应的bash进程,bash进程收到这个信号后首先将它发给session下面的进程,如果你的程序没有对SIGHUP信号做特殊处理,那么进程就会随着终端关闭而退出。

<think>嗯,用户问为什么关闭终端后Filebeat进程也会终止。我需要解释背后的原因,可能涉及终端会话、进程组和守护进程的概念。用户可能是在直接运行Filebeat命令而没有使用后台模式或者服务管理工具,导致进程绑定到终端会话。当终端关闭,系统会发送SIGHUP信号,导致进程终止。 首先,我应该确认用户是如何启动Filebeat的。比如,是否用了nohup、&或者直接运行。然后,解释终端关闭的影响,比如会话结束导致进程收到信号。接着,提供解决方法,比如使用后台模式、nohup、systemd服务或者配置文件中的守护进程选项。 可能用户是新手,不太了解Linux进程管理,所以需要详细说明每个步骤,并给出具体的命令示例。同,提醒用户权限问题,比如使用sudo来安装服务。还要注意安全退出,避免数据丢失,建议正确的停止命令。 需要检查之前的对话历史,用户之前问过配置文件中的重复项,现在遇到进程管理问题。可能需要联系之前的配置问题,但这次主要回答进程终止的原因和解决方法。确保回答结构清晰,分点说明原因和解决方案,让用户容易理解。</think>当你关闭终端后,Filebeat 进程自动终止,通常是因为 **Filebeat 进程终端会话(Terminal Session)绑定**,关闭终端系统会向所有关联的进程发送终止信号(如 `SIGHUP`)。以下是具体原因和解决方法: --- ### **原因分析** 1. **前台运行模式** 如果你直接通过终端前台运行 Filebeat(例如 `./filebeat -c filebeat.yml`),进程会绑定到当前终端会话。关闭终端,系统会发送 `SIGHUP` 信号,导致进程终止。 2. **未配置守护进程模式** Filebeat 默认不会以守护进程(Daemon)形式运行,需要显式配置或通过系统服务管理工具(如 `systemd`)启动。 3. **依赖终端输出** 如果 Filebeat 的日志输出直接关联到终端(未重定向到文件或系统日志),关闭终端可能中断其日志流,间接导致进程退出。 --- ### **解决方法** #### **1. 使用后台运行模式 (`&` + `nohup`)** 通过 `nohup` 忽略 `SIGHUP` 信号,并将输出重定向到文件: ```bash nohup ./filebeat -c filebeat.yml > filebeat.log 2>&1 & ``` - `nohup`: 忽略终端关闭的挂断信号。 - `> filebeat.log 2>&1`: 将标准输出和错误输出重定向到文件。 - `&`: 将进程放入后台运行。 #### **2. 启动添加 `--daemon` 参数** Filebeat 支持以守护进程模式运行: ```bash ./filebeat -c filebeat.yml --daemon ``` #### **3. 使用系统服务管理(推荐)** 通过 `systemd` 将 Filebeat 注册为系统服务,实现开机自启和自动守护: - **创建服务文件**(如 `/etc/systemd/system/filebeat.service`): ```ini [Unit] Description=Filebeat After=network.target [Service] User=root ExecStart=/usr/share/filebeat/bin/filebeat -c /etc/filebeat/filebeat.yml --path.data /var/lib/filebeat --path.logs /var/log/filebeat Restart=always [Install] WantedBy=multi-user.target ``` - **启用并启动服务**: ```bash sudo systemctl daemon-reload sudo systemctl enable filebeat sudo systemctl start filebeat ``` #### **4. 使用 `screen` 或 `tmux` 保持会话** 通过终端复用工具(如 `screen`/`tmux`)保持进程独立于终端: ```bash # 安装 screen sudo apt-get install screen # 创建新会话并运行 Filebeat screen -S filebeat_session ./filebeat -c filebeat.yml # 按 Ctrl+A 后按 D 脱离会话(进程继续运行) # 重新连接:screen -r filebeat_session ``` --- ### **验证进程状态** - 检查 Filebeat 是否在后台运行: ```bash ps aux | grep filebeat ``` - 查看日志确认运行状态: ```bash tail -f /var/log/filebeat/filebeat ``` --- ### **注意** - **权限问题**:若以 `sudo` 启动关闭终端可能不会终止进程(取决于具体环境)。 - **配置文件路径**:确保 `filebeat.yml` 路径正确,否则进程可能启动失败。 - **优雅退出**:若需停止 Filebeat,使用 `kill` 或服务命令(如 `systemctl stop filebeat`),避免直接终止进程导致数据丢失。 通过以上方法,Filebeat 进程将不再依赖终端会话,关闭终端后仍可保持运行。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值