cen's blog cen's blog
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • 《JavaScript教程》
    • C++学习
    • C++数据结构
    • MySQL
    • Linux
  • 高中时代
  • 工作日常
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)

cen

十年饮冰,难凉热血
首页
  • 编程文章

    • markdown使用
  • 学习笔记

    • 《JavaScript教程》
    • C++学习
    • C++数据结构
    • MySQL
    • Linux
  • 高中时代
  • 工作日常
  • CLion
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 分类
  • 标签
  • 归档
关于
GitHub (opens new window)
  • Linux环境搭建
  • 基本指令
  • 权限
  • Linux基础开发工具
  • 进程概念
  • 进程控制
  • 基础IO流
  • 动态库和静态库
  • 进程通信
  • 进程信号
    • 信号基础
    • 产生信号
      • 通过系统函数
      • 核心转储
    • 阻塞信号
      • 信号其他相关常见概念
      • 在内核中的表示
      • 捕捉信号
      • 内核空间和用户空间
      • 内核态和用户态
  • 多线程
  • 线程安全
  • Linux
cen
2025-04-14
目录

进程信号

# 信号基础

使用kill -l命令列出所有信号

[cen@VM-4-9-opencloudos lesson03-进程通信]$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
# [1, 31]:普通信号
# [32, 64]:实时信号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

信号的记录

进程接收到信号时可能有更重要的代码,所以信号不一定被立即处理,并且进程要有对信号的保存能力

【保存在task_struct中,用位图来保存,其中比特位的位置:代表信号编号,比特位的内容:是否接收到信号】

例如0000 0000 0000 0000 0000 0000 0000 0000,接收6号信号时,修改为0000 0000 0000 0000 0000 0000 0010 0000

信号的产生

一个进程收到信号,本质就是该进程内的信号位图被修改了,也就是该进程的数据被修改了,而只有操作系统才有资格修改进程的数据,因为操作系统是进程的管理者。也就是说,信号的产生本质上就是操作系统直接去修改目标进程的task_struct中的信号位图,由OS完成(调用相关系统接口)

信号的处理

进程在处理信号时有三种动作:默认、自定义(也称捕捉一个信号)和忽略。

查看各个信号默认的处理动作man 7 signal:

The entries in the "Action" column of the table below specify the default disposition for each signal, as follows:

Term   Default action is to terminate the process.

Ign    Default action is to ignore the signal.

Core   Default action is to terminate the process and dump core (see core(5)).

Stop   Default action is to stop the process.

Cont   Default action is to continue the process if it is currently stopped.
1
2
3
4
5
6
7
8
9
10
11

# 产生信号

# 通过系统函数

  1. kill命令
#include <signal.h>
int kill(pid_t pid, int sig);
1
2

kill函数用于向进程ID为pid的进程发送sig号信号,如果信号发送成功,则返回0,否则返回-1

示例:

mysignal

#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <signal.h>

void Usage() {
    std::cout << "Usage: ./Mysignal pid signo" << std::endl;
}

int main(int argc, char *argv[]) {
    if(argc != 3) {
        Usage();
        exit(1);
    }
    pid_t pid = atoi(argv[1]);
    int signo = atoi(argv[2]);
    int n = kill(pid, signo);
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

test.cpp

#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>

int main(int argc, char *argv[]) {
    while(true) {
        std::cout << "一段运行的进程" << getpid() << ":print Hello World!" << std::endl;
        sleep(2);
    }
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11

运行 窗口1:

[cen@VM-4-9-opencloudos mysignal]$ make
g++ -o test test.cpp -std=c++11 -g
g++ -o Mysignal mysignal.cpp -std=c++11
[cen@VM-4-9-opencloudos mysignal]$ ./test
一段运行的进程2018165:print Hello World!
一段运行的进程2018165:print Hello World!
一段运行的进程2018165:print Hello World!
一段运行的进程2018165:print Hello World!
一段运行的进程2018165:print Hello World!
一段运行的进程2018165:print Hello World!
一段运行的进程2018165:print Hello World!
Killed
1
2
3
4
5
6
7
8
9
10
11
12

窗口2:

[cen@VM-4-9-opencloudos mysignal]$ ./Mysignal
Usage: ./Mysignal pid signo
[cen@VM-4-9-opencloudos mysignal]$ ./Mysignal 2018165 9
[cen@VM-4-9-opencloudos mysignal]$ 
1
2
3
4
  1. raise函数

raise函数可以给当前进程发送指定信号,即自己给自己发送信号,raise函数的函数原型如下:

int raise(int sig);
1
  1. abort函数

abort函数可以给当前进程发送SIGABRT信号,使得当前进程异常终止,abort函数的函数原型如下:

void abort(void);
1

# 核心转储

Action为core时:Core Default action is to terminate the process and dump core[核心转储] (see core(5)).

核心转储是默认被关掉的,我们可以通过使用ulimit -a命令查看当前资源限制的设定。 我们可以通过ulimit -c size命令来设置core文件的大小,从而打开核心存储。

[cen@VM-4-9-opencloudos lesson03-进程通信]$ ulimit -a
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) unlimited
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 6680
max locked memory           (kbytes, -l) 8192
max memory size             (kbytes, -m) unlimited
open files                          (-n) 524288
pipe size                (512 bytes, -p) 8
POSIX message queues         (bytes, -q) 819200
real-time priority                  (-r) 0
stack size                  (kbytes, -s) 8192
cpu time                   (seconds, -t) unlimited
max user processes                  (-u) 6680
virtual memory              (kbytes, -v) unlimited
file locks                          (-x) unlimited
[cen@VM-4-9-opencloudos lesson03-进程通信]$ ulimit -c 1024
[cen@VM-4-9-opencloudos lesson03-进程通信]$ ulimit -a
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 1024
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 6680
max locked memory           (kbytes, -l) 8192
max memory size             (kbytes, -m) unlimited
open files                          (-n) 524288
pipe size                (512 bytes, -p) 8
POSIX message queues         (bytes, -q) 819200
real-time priority                  (-r) 0
stack size                  (kbytes, -s) 8192
cpu time                   (seconds, -t) unlimited
max user processes                  (-u) 6680
virtual memory              (kbytes, -v) unlimited
file locks                          (-x) unlimited
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

使用:

当我们的程序在运行过程中崩溃了,我们一般会通过调试来进行逐步查找程序崩溃的原因。而在某些特殊情况下,我们会用到核心转储,核心转储指的是操作系统在进程收到某些信号而终止运行时,将该进程地址空间的内容以及有关进程状态的其他信息转而存储到一个磁盘文件当中,这个磁盘文件也叫做核心转储文件,一般命名为core.pid,方便问题的定位。

[cen@VM-4-9-opencloudos mysignal]$ make
g++ -o Mysignal mysignal.cpp -std=c++11
[cen@VM-4-9-opencloudos mysignal]$ ./Mysignal 
3728615 Hello World!
3728615 Hello World!
3728615 Hello World!
^\Quit (core dumped)
# Ctrl + \ : SIGQUIT      P1990      Core    Quit from keyboard
[cen@VM-4-9-opencloudos mysignal]$ ll
total 32
-rw-r--r-- 1 cen cen   340 Apr 20 17:44 Makefile
-rwxr-xr-x 1 cen cen 17088 Apr 20 18:01 Mysignal
-rw-r--r-- 1 cen cen   549 Apr 20 17:48 mysignal.cpp
-rw-r--r-- 1 cen cen   250 Apr 16 20:15 test.cpp
[cen@VM-4-9-opencloudos mysignal]$ coredumpctl
Hint: You are currently not seeing messages from other users and the system.
      Users in groups 'adm', 'systemd-journal', 'wheel' can see all messages.
      Pass -q to turn off this notice.
TIME                            PID  UID  GID SIG     COREFILE EXE                                                                                 >                              >
Sun 2025-04-20 18:01:51 CST 3728615 1001 1001 SIGQUIT present  /home/cen/Linux/lesson03-进程通信/mysignal/Mysignal  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 阻塞信号

# 信号其他相关常见概念

  1. 实际执行信号的处理动作,称为信号递达(Delivery)。
  2. 信号从产生到递达之间的状态,称为信号未决(pending)。
  3. 进程可以选择阻塞(Block)某个信号。
  4. 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
  5. 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后的一种处理动作。

# 在内核中的表示

有两张位图pending和block和一个数组handler表:

  • unsigned int pending 比特位的位置表示信号编号, 比特位的内容表示是否收到对应信号
  • unsigned int block 比特位的位置表示信号编号, 比特位的内容表示是否阻塞对应信号
  • 函数指针数组handler表,数组的下标代表某一个信号,数组的内容代表该信号递达时的处理动作,处理动作包括默认、忽略以及自定义。

# 捕捉信号

# 内核空间和用户空间

信号在产生的时候不会被立即处理而是在合适的时候(从内核态到用户态的时候进行处理)

用户态为了访问内核或硬件资源,必须通过系统调用完成访问

每一个进程都有自己的进程地址空间,该进程地址空间由内核空间和用户空间组成:

  • 用户所写的代码和数据位于用户空间,通过用户级页表与物理内存之间建立映射关系。
  • 内核空间存储的实际上是操作系统代码和数据,通过内核级页表与物理内存之间建立映射关系。
  • 内核级页表是一个全局的页表,它用来维护操作系统的代码与进程之间的关系。因此,在每个进程的进程地址空间中,用户空间是属于当前进程的,每个进程看到的代码和数据是完全不同的,但内核空间所存放的都是操作系统的代码和数据,所有进程看到的都是一样的内容。

# 内核态和用户态

内核态与用户态:

内核态通常用来执行操作系统的代码,是一种权限非常高的状态。 用户态是一种用来执行普通用户代码的状态,是一种受监管的普通状态。 进程收到信号之后,并不是立即处理信号,而是在合适的时候,这里所说的合适的时候实际上就是指,从内核态切换回用户态的时候。

P29 + P30

上次更新: 2025/05/04, 22:48:52
进程通信
多线程

← 进程通信 多线程→

最近更新
01
线程安全
05-21
02
cmake教程
05-08
03
项目
05-07
更多文章>
Theme by Vdoing | Copyright © 2024-2025 京ICP备2020044002号-3 京公网安备11010502056119号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式