【Linux】进程信号及相关函数/系统调用的简单认识与使用

文章目录

  • 前言
  • 一、相关函数/系统调用
    • [1. signal](#1. signal)
    • [2. kill](#2. kill)
    • [3. abort (库函数)](#3. abort (库函数))
    • [4. raise (库函数)](#4. raise (库函数))
    • [5. alarm](#5. alarm)

前言

现实生活中, 存在着诸多信号, 比如红绿灯, 上下课铃声...我们在接收到信号时, 就会做出相应的动作. 对于进程也是如此的, 进程也会收到来自 OS 发出的信号, 根据信号的不同也会做出不同的动作, 进程在收到信号时也并不一定会立即执行, 也可以在适当的时候在执行该信号对应的动作, 一般信号常见处理方式有如下三种:

  1. 忽略此信号.
  2. 执行该信号的默认处理动作.
  3. 提供一个信号处理函数, 要求内核在处理该信号时切换到用户态执行这个处理函数, 这种方式称为捕捉一个信号.

而在进程中用以保存信号的容器可以是一个位图, 通过 0, 1 来表示是否收到某信号.

在 Linux 中, 可以通过指令:

bash 复制代码
kill -l

来查看系统定义的信号列表:

通过指令:

bash 复制代码
man 7 signal

可以查看关于信号的详细说明:

在 Linux 中可以通过指令:

bash 复制代码
kill -信号编号 进程pid

来对指定进程发送指定信号.

一、相关函数/系统调用

1. signal

头文件: #include <signal.h>

函数声明: sighandler_t signal(int signum, sighandler_t handler);

  • signum: 被设置的信号编号.
  • handler: 被设置的信号的新的处理函数, 是一个回调函数, 通过用户传递.
  • sighandler_t: 是一个函数指针, 可以指向一个返回值为 void, 参数为 int 的函数, 以下是系统中的 typedef:
    typedef void (*sighandler_t)(int);

功能: 将指定的信号的处理函数覆盖为 handler.

示例代码:

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;

void sighandler(int signo)
{
    cout << "void sighandler(int signo): " << signo << endl;
}

int main()
{
    signal(2, sighandler);
    while(1)
    {
        cout << "Hello" << endl;
        sleep(1);
    }
    return 0;
}

运行结果:

实际 Ctrl + C 就是编号为 2 的信号, 平常通过 Ctrl + C 向进程发送 SIGINT(2) 号信号, 可以终止进程, 但是把信号 2 的处理函数换成了自定义的, 所以在终端按下 Ctrl + C 时执行我们自定义的函数.

PS: 9, 18, 19 号信号即时被重定向了新的处理函数也没用, 该信号仍然会执行原本的处理函数.

2. kill

头文件:

#include <sys/types.h>

#include <signal.h>

函数声明: int kill(pid_t pid, int sig);

  • pid: 目标进程pid.
  • sig: 向目标发送的信号编号.

功能: 向指定进程发送指定信号.

示例代码:

cpp 复制代码
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
using namespace std;

int main()
{
    for(int i = 0; i < 10; ++i)
    {
    	if(i == 5)
        {
            kill(getpid(), 9);
        }
        cout << i << ":Hello" << endl;
        sleep(1);
    }
    return 0;
}

运行结果:

在输出 5 条语句后, 向自己发送 9 号信号, 直接终止自己了.

3. abort (库函数)

头文件: #include <stdlib.h>

函数声明: void abort(void);

功能: 向调用进程发送终止信号.

示例代码:

cpp 复制代码
#include <iostream>
#include <cstdlib>
#include <unistd.h>
using namespace std;

int main()
{
    for(int i = 0; i < 10; ++i)
    {
        if(i == 5)
        {
            abort();
        }
        cout << i << ":Hello" << endl;
        sleep(1);
    }
    return 0;
}

运行结果:

4. raise (库函数)

头文件: #include <signal.h>

函数声明: int raise(int sig);

  • 返回值: 成功调用返回 0, 失败返回非零整数.
  • sig: 信号编号.

功能: 向调用进程发送指定信号.

示例代码:

cpp 复制代码
#include <iostream>
#include <csignal>
#include <unistd.h>
using namespace std;

int main()
{
    for(int i = 0; i < 10; ++i)
    {
        if(i == 5)
        {
            raise(9);
        }
        cout << i << ":Hello" << endl;
        sleep(1);
    }
    return 0;
}

运行结果:

5. alarm

头文件: #include <unistd.h>

函数声明: unsigned int alarm(unsigned int seconds);

  • 返回值: 返回一个无符号整数, 表示前一个闹钟剩于的秒数, 打个比方, 闹钟设置为 30s 后响, 但是在 20s 的时候就收到了 SIGALRM(14) 信号, 此时闹钟会提前响, 返回值就为 30 - 20 = 10.
  • seconds: 多少秒后响铃.

功能: 在过了 seconds 秒以后终止调用进程.

示例代码:

cpp 复制代码
#include <iostream>
#include <unistd.h>
using namespace std;

int main()
{
    alarm(1);
    for(int i = 0; ; i++)
    {
        cout << i << ":Hello" << endl;
    }
    return 0;
}

运行结果:

可以看到, 在 1 秒钟后闹钟响了, 进程也就被终止了.

接下来通过另一段代码查看返回值:

cpp 复制代码
#include <iostream>
#include <signal.h>
#include <unistd.h>
using namespace std;

void sighandler(int signo)
{
    cout << "void sighandler(int signo): " << signo << endl;
    int n = alarm(10);
    cout << "n: " << n << endl;
}

int main()
{
    cout << "pid:" << getpid() << endl;
    signal(SIGALRM, sighandler);
    alarm(10);
    while(1);
    return 0;
}

运行结果:

可以看到, 在闹钟设定后, 以我最快的速度给调用闹钟的进程发送 14 号信号之后, 返回的剩于秒数为 8s, 也就是说闹钟只跑了 2s, 而后又设置了一个 10s 后响的闹钟, 这次没有提前发送 14 号信号, 它正常跑完, 返回的剩于秒数为 0s, 合理.

相关推荐
U盘失踪了3 小时前
python JSONPath 表达式生成器
linux·windows·python
锦鲤飞上天5 小时前
CentOS卸载、安装MySQL8(yum操作)
linux·adb·centos
mortimer5 小时前
一次搞懂 rsync:从入门到解决真实世界中的权限难题
linux·运维·centos
wb1897 小时前
服务器的Mysql 集群技术
linux·运维·服务器·数据库·笔记·mysql·云计算
huangyuchi.8 小时前
【Linux系统】详解,进程控制
linux·进程控制·进程创建·进程等待·进程程序替换·退出码·进程终止
zly35009 小时前
Linux(centos)安全狗
linux·运维·服务器
失因9 小时前
Linux 权限管理与 ACL 访问控制
linux·运维·服务器·数据库·centos
玖剹10 小时前
Linux文件操作:从C接口到系统调用
linux·服务器·c语言·c++·笔记·ubuntu
Lovyk11 小时前
Linux 系统启动原理
linux·服务器·windows
藏在歌词里11 小时前
Linux-Shell脚本基础用法
linux·运维·服务器