Linux C++通讯架构【二】:进程和信号

终端(pts)与进程的关系

  1. pts就是一个bash(命令解释器),一个shell,一个可执行程序,在/bin/bash目录下,终端如果关闭,终端上的进程也就关闭了;
  • 比如执行一个可执行程序,不断往A终端printf数据,然后新开一个终端B,通过ps -la命令可以看到这个printf的进程,但是当A终端关闭后,ps查看进程发现这个printf的进程不在了

因为这个printf进程属于一个进程组,同一个进程组的进程组id相同,都是bash进程的子进程 (ps命令查看父进程可知),所以xshell其实并不是远程控制,而是一个实际的远程终端

  1. 会话(session):一个或多个进程组的集合。一个bash上有多个进程组,一般bash的所有进程都属于一个session,但也可能一个bash上有多个session

记录个命令:ps -eo pid,ppid,sid,tty,pgrp,comm | grep -E 'bash|PID|nginx' 其中,-o参数表示自定义展示哪些列,sid表示sessionid,tty表示终端(0,1,2是啥意思),pgrp表示进程组,-E表示正则匹配

  1. bash: shell的一种,linux默认采用bash这种shell,也就是说bash是一个可执行程序,主要作用是把用户输入的命令翻译给操作系统(命令解释器)。在/bin/bash目录,输入exit就可以logout这个终端

终端与信号

当终端要退出时,系统会发送SIGHUP信号(终端断开信号),给session_leader(一般就是bash进程,也可以调系统函数自己设置),bash进程收到SIGHUP信号后, 会把这个信号发送给所有sessionid相同的进程(如nginx子进程),然后再给自己发送SIGHUP信号。

strace信号跟踪工具:可以跟踪程序执行时进程的系统调用,以及所收到的信号,如在其他终端执行命令: sudo strace -e trace=signal -p 1359附着1359这个bash进程,然后关掉这个bash终端,查看输出

  • 怎么让bash退出,Nginx不退出
  • Nginx拦截操作系统的sighup信号:nginx启动时,加一行代码signal(SIGHUP,SIG_IGN);,SIG_IGN表示忽略某一种信号
    • 这种情况由于bash父进程死了,将变成孤儿进程由Init进程接管,也就是ppid变成1了
  • 设置Nginx的sessionid,新建一个session,和bash不在同一个会话里:nginx启动时,加一行代码setsid();
    • 进程组组长不能setid(),这在创建守护进程会提到。解决方法,fork一个子进程
    • setsid命令,可改变一个已启动进程的sessionid
C++ 复制代码
#include<signal.h>

int main(int argc, char* const *argv){
    pid_t pid;
    printf("内容输出");
    pid=fork();   // 系统函数,子进程会从fork()调用之后开始执行
    if(pid<0){
        printf("子进程设置出错")
    }else if(pid==0){   // 子进程
        setsid();  // 子进程新建一个不同的session4
    }else{   // 父进程
        // signal(SIGHUP,SIG_IGN);
    }
    // ....逻辑代码
}

后台运行:

  • nginx执行自己的程序,终端可以继续处理其他的;
  • fg切换到前台,终端输入的指令Nginx都不会例会了
  • 后台运行可以往终端打印东西

信号

信号都是突发事件,异步发生,也称为软件中断,进程收到信号,操作系统都会知道

记录一条命令:find / -name "signal.h" | xargs grep -in "SIGHUP",其中,xargs表示找到文件后,将文件内容传输给grep进行查找 信号产生:

  • 某个进程发送给另一个进程或自己(Nginx热升级)
  • 内核发送给某个进程 :
    • ctrl+c(中断信号),kill命令
    • 内存访问异常,硬件通知内核,内核通知进程 信号都以SIG开头,如SIGHUP,信号都是一些正整数常量(signal.h中的宏定义,从1开始)

kill

我们在关闭bash时,bash会用kill命令发送一个SIGTERM信号,关闭nginx进程

用来发送信号,信号9定义为SIGKILL,kill -9 pid表示给进程发送一个SIGKILL的信号

然后,kill -1 pid表示挂起这个进程(信号1定义为SIGHUP),然而,神奇的是,这个进程直接被杀掉了 =》 这是由于操作系统给进程发送信号后,如果进程没有对这个信号做出处理,操作系统默认会杀死这个进程(之所以将信号发送命令命名为kill,就是因为绝大部分操作系统发送的信号的缺省操作就是杀死)

同理,kill pid也可以杀死进程

kill的常用参数:

内核态和用户态

malloc()和printf(),会先切换到内核态,再切换回用户态。其实printf内部就会调用malloc()

什么时候会从用户态切到内核态:

  • 系统调用:malloc()
  • 异常事件:比如来了个信号
  • 外围设备中断

信号集:

Linux支持60多种信号,信号集是一种数据结构,0011000...,可简单理解为64多个bit(其实是一个sigset_t结构)

C++ 复制代码
typedef struct{
    unsigned long sig[2];   // 一个long4bit,两个正好8bit
    // 相关api自行百度
}sigset_t;

来一个信号对应位置置为1,如果本来就为1,说明同类型信号正在被处理,不能被打断,得排队。 如果一个信号处理函数正在处理其他信号,后续相同的信号统统归结为1次,并被阻塞到上个信号处理完。 信号屏蔽:一个进程有一个信号集,我们可以把要屏蔽的信号位设为1,就能实现信号阻塞了(sigprocmask()函数)。

相关推荐
A小辣椒5 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒9 小时前
TShark:基础知识
linux
AlfredZhao11 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334661 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪1 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言