Linux信号解析

这篇具有很好参考价值的文章主要介绍了Linux信号解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

Linux信号概念

信号在我们的生活中无处不在,常见的如电话铃声,闹钟等,这些的信号都是给我们传达某些信息,在接收到信息之后来选择采取什么样的措施,因此我们可以将信号理解为传达信息的事物。在Linux中也有这么一批信号,信号是操作系统提供的一种机制,用于通知进程发生了某种事件或异常情况。当特定的事件发生时(例如按下 Ctrl+C 来中断程序),操作系统会生成相应的信号,并将其发送给目标进程。总之,信号是操作系统提供的一种重要的进程间通信机制,操作系统捕获和分发信号,允许进程对信号进行响应和处理。

信号种类

Linux中有多种不同的信号,每个信号都有一个编号和一个宏定义名称,例如1表示SIGHUP,2表示SIGINT等等,这些宏定义可以在signal.h中找到。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

在linux中也可以用kill -l命令来查看信号,以下信号可以分为两个主要类别:实时信号和标准信号。实时信号是为了满足实时应用程序的需求而引入的,具有较高的优先级和可预测的传递和处理时间。实时信号的信号编号通常在34到64之间,例如SIGRTMIN、SIGRTMIN+1等。它们具有实时信号队列,按照顺序接收和处理,以确保信号的顺序性。实时信号有两个优先级:实时信号和实时时钟信号。

标准信号是常规的信号类型,用于各种进程通信、控制和处理异常情况。标准信号的信号编号通常在1到31之间,包括SIGINT、SIGHUP、SIGTERM等。它们没有明确定义的优先级,信号处理通常较为基本。这两种信号类型都用于与进程通信、控制进程行为和处理各种事件。实时信号主要用于实时应用,而标准信号则更常用于一般用途的进程间通信和控制。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

Linux信号产生

Linux信号可以通过多种方式产生,通常由内核、其他进程或硬件事件触发。例如进程终止或错误时也会产生信号进程执行发生错误时,如除以零,产生SIGFPE信号,进程访问未分配给它的内存或无效内存时,产生SIGSEGV信号。当用户在终端按下Ctrl+C会产生SIGINT信号。用户在终端按下Ctrl+\,产生SIGQUIT信号。用户按下Ctrl+Z,将进程置于后台并产生SIGTSTP信号。

在某些情况下,系统调用失败也会产生特定的信号,如SIGPIPE。这些信号产生方式可以由操作系统、应用程序或用户发起。处理这些信号可以通过注册信号处理函数来定义接收到信号时要执行的特定操作。例如可以使用kill命令向另一个进程发送信号。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

此外还可以使用kill()函数向另一个进程发送信号,kill 函数通常用于终止一个进程。它是Unix和类Unix操作系统中的系统调用之一。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

它的参数 pid代表的是要终止的进程的进程ID(PID)。sig表示要发送给目标进程的信号。通常,SIGTERM(15号信号)用于请求优雅地终止进程,而SIGKILL(9号信号)用于强制终止进程。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

如果成功发送信号,则返回0。如果失败,则返回-1,并设置errno来指示错误的原因。如下代码:

void Usage(string str)
{
    cout << "Usage : \n\t";
    cout << str << "int sig   pid_t pid" << endl;
}

int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    int signo = atoi(argv[1]);
    int target_id = atoi(argv[2]);
    int ret = kill(target_id, signo);  //给指定进程发送指定信号
    if(ret == -1)
    {
        cout << errno << strerror(errno) << endl;
    }
    return 0;
}

这是一个简单的C++程序,用于给指定的进程发送信号。Usage 函数用于打印程序的用法说明,它接受一个字符串参数 str,用 cout 打印用法信息。main 函数首先检查命令行参数的数量,如果不等于3个(期望的参数数量),则调用 Usage 函数打印用法信息,并使用 exit(1) 终止程序。如果命令行参数数量正确,它将解析这两个参数为整数 signo 和 target_id,分别表示要发送的信号和目标进程的PID。然后,调用 kill 函数来向指定的进程发送指定的信号,并将返回值存储在 ret 变量中。最后,程序检查 kill 函数的返回值,如果返回值为-1,表示发送信号失败。它将使用 errno 和 strerror 函数来打印错误信息。结果如下:

Linux信号解析,Linux,linux,服务器,c++,网络,运维

异步

异步是指在程序执行过程中,某个操作可以独立于主程序流程,不阻塞主程序的执行,而在完成后通知主程序或回调执行相应的处理。简而言之,异步操作允许程序在等待某些事件完成的同时,可以继续执行其他任务。举例来说,假设你在下载一个大文件,如果是同步操作,程序会一直等待下载完成才能进行其他操作。而异步下载则会允许你在下载的同时执行其他任务,当下载完成时会通过回调或其他机制通知你。异步通常用于处理需要等待的操作,比如网络请求、文件读写、图形界面事件等。它可以提高程序的响应性和效率,因为在等待某些操作完成的同时,可以执行其他任务,充分利用了计算资源。

而信号相对于进程的控制流程来说就是异步的,因为对于进程来说,信号来源不确定,信号可以来自多种来源,包括其他进程、操作系统或硬件事件。进程无法预测何时会收到信号,因此无法像在同步控制流程中那样精确地安排信号的处理。并且信号可以随时中断进程,当进程正在执行某个任务时,随时可能收到信号。这个信号会中断进程当前的执行,转而执行与信号相关联的信号处理函数。这种中断式的行为使得信号处理是异步的,因为进程无法控制何时会被中断。信号处理被时间也是不确定的,信号处理函数的执行时间是不确定的,取决于信号的类型和处理函数的复杂性。进程无法预测信号处理将花费多长时间,因此无法以确定的方式管理信号的异步性质。

综上所述,可以说信号相对于进程的控制流程来说是异步,因为它们可以在进程不预期的时间中断进程的执行,且信号的来源和处理时间都是不确定的,无法由进程精确地控制。这使得处理信号的机制更加灵活,但也需要谨慎处理,以确保进程的稳定性和可靠性。

LInux信号阻塞

Linux中的信号阻塞是一种机制,它可以防止特定信号在某段代码执行期间被中断。这样可以确保关键部分的代码不会被信号中断,从而保证程序的一致性和可靠性。

递达、未决、阻塞、忽略

递达、未决、阻塞、忽略这些术语通常用于描述与信号处理相关的状态和操作:

  • 信号递达(Delivered):表示信号已经成功传递给目标进程,但目标进程尚未开始处理信号。信号已经到达进程的信号队列中,等待被处理。
  • 信号未决(Pending):未决状态表示信号已经递达,但目标进程还没有处理完该信号。在某些情况下,一个进程可以同时拥有多个未决信号,这些信号排队等待处理。
  • 信号阻塞(Blocked):阻塞表示进程已经将某些信号阻塞,即在信号掩码中将这些信号的位设置为1。阻塞信号的目的是防止它们在关键代码段执行期间中断进程。
  • 信号忽略(Ignored):忽略表示进程对特定信号的处理方式是忽略。当进程忽略信号时,该信号不会触发默认的操作或用户定义的信号处理函数,而会被静默忽略。

这些概念一起用于描述进程如何处理信号。例如,一个进程可以选择忽略某些信号,将其他信号阻塞以在关键部分执行时不被中断,然后处理已递达但未决的信号。递达和未决信号的状态告诉我们哪些信号已经到达,哪些正在等待被处理。信号处理是进程中管理这些状态的关键部分。

注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

信号集操作函数

在操作系统中,通常会有三张表与信号处理相关:阻塞表(Block Table)、未决表(Pending Table) 和 处理程序表(Handler Table)。这些表用于管理和描述进程的信号处理状态和方式。

block表维护了有关哪些信号被当前进程阻塞的信息,对于每个进程,内核会维护一个信号掩码,该掩码是一个位掩码,用于表示哪些信号被阻塞,哪些可以传递给进程。控制信号掩码可以通过系统调用如 sigprocmask 进行,使进程可以选择性地阻塞或解除阻塞信号。

pending表记录了哪些信号已经被递送给进程,但尚未被处理。每个进程都有一个未决信号集合,这些信号在被递送后保持未决状态,直到被处理。未决信号的状态可以在内核中进行管理,以确保每个信号都得到适当的处理。

handler表是一个数据结构,用于将信号与它们的处理方式(处理函数)相关联。对于每个信号,内核会维护一个处理程序表,记录了该信号的默认操作或用户自定义处理函数。当进程接收到一个信号时,内核会查找相应信号的处理程序表,并执行与之相关联的处理函数。

这三张表协同工作,允许进程管理信号的接收和处理。阻塞表控制哪些信号会被阻塞,未决表跟踪哪些信号等待处理,而处理程序表定义了每个信号的行为。这些机制使进程能够在异步情况下处理信号,以应对不同类型的事件和通信。

Linux中常规信号在递达之前产生多次的话只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里统计多次。

从这里就可以知道,每个信号只有一个 bit 的未决和阻塞标志,不是0就是1。因此在Linux中未决和阻塞标志可以用相同的数据类型sigset_t来存储。sigset_t 是一个数据类型,通常用于表示信号集合,用于管理和操作一组信号的状态。它是 POSIX 标准中定义的一种数据类型,用于在信号处理中指定和操作一组信号。sigset_t 通常是一个用于存储信号掩码的数据结构。信号掩码是一个位掩码,其中每一位对应一个特定的信号。如果某个信号的位被设置为 1,表示该信号被阻塞;如果为 0,表示该信号可以传递给进程。通过设置和修改 sigset_t 对象,可以实现对信号的阻塞和解除阻塞。以下是一些与 sigset_t 相关的常用函数和操作:

Linux信号解析,Linux,linux,服务器,c++,网络,运维

  • sigemptyset(sigset_t *set):用于初始化一个空的信号集合,即将所有信号位都设置为 0。
  • sigfillset(sigset_t *set):用于将一个信号集合设置为包含所有可能的信号,即将所有信号位都设置为 1。
  • sigaddset(sigset_t *set, int signum):用于将指定信号添加到信号集合中,将对应信号位设置为 1。
  • sigdelset(sigset_t *set, int signum):用于从信号集合中移除指定信号,将对应信号位设置为 0。
  • sigismember(const sigset_t *set, int signum):用于检查指定信号是否包含在信号集合中。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。其他四个函数都是成功返回0,出错返回-1。sigset_t 对象通常在信号处理函数中使用,以防止在关键代码段执行时被特定信号中断。通过操作 sigset_t 对象,可以实现对信号的精细控制和管理。

阻塞信号集操作函数

对于进程的阻塞信号集可以调用函数sigprocmask来读取或更改,sigprocmask 是一个 POSIX 标准定义的系统调用,该系统调用的函数原型如下:

Linux信号解析,Linux,linux,服务器,c++,网络,运维
其中 how 参数指定了如何修改信号屏蔽字,有以下3种选择:

  • SIG_BLOCK:将 set 中的信号添加到当前的信号屏蔽字中。
  • SIG_UNBLOCK:从当前的信号屏蔽字中移除 set 中的信号。
  • SIG_SETMASK:将当前的信号屏蔽字设置为 set 中的值。

set 参数和 oldset 参数都是一个指向 sigset_t 类型的指针,set 参数包含了要设置的新的信号屏蔽字。oldset 参数用于存储调用 sigprocmask 前的信号屏蔽字。如果不关心原始的信号屏蔽字,可以将 oldset 设为 NULL。

未决信号集操作函数

对于进程的未决信号集可以用 sigpending 函数来查看,sigpending 是一个 POSIX 标准定义的函数,用于检索当前进程中的未决信号,函数原型如下:

Linux信号解析,Linux,linux,服务器,c++,网络,运维
set 参数是一个指向 sigset_t 类型的指针,用于存储检测到的未决信号。这个函数会将当前进程中的未决信号的信号集合存储到 set 中。sigpending 函数通常在信号处理程序中使用,以确定哪些信号在当前上下文中已经到达但尚未被处理。未决信号的检查可以帮助进程采取相应的行动来处理这些信号,比如选择性地解除信号阻塞、执行相应的处理程序等。

未决信号是在 sigpending 函数被调用时确定的,因此在函数返回后,仍然可能会有新的信号到达并成为未决信号。

Linux信号捕捉

Linux的信号产生之后,就需要有东西能接收到这个信号,然后在决定接收到这个信号后采取什么样的措施。如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。

signal函数

在Linux中,可以通过注册信号处理函数来捕捉信号,以定义在接收到特定信号时要执行的操作。其中就可以使用signal()函数来对信号进行捕捉处理,signal()函数是用于在Linux和UNIX系统中注册信号处理函数的函数之一,它的原型如下:

Linux信号解析,Linux,linux,服务器,c++,网络,运维

signal()函数的主要作用是告诉操作系统,在接收到特定信号(由signum指定)时,去调用特定的信号处理函数(由handler指定)。这个函数返回一个函数指针,该指针指向以前注册的信号处理函数(通常是默认处理方式)。一般你可以忽略这个返回值,但如果需要以后恢复默认的信号处理行为的话就可以使用它。如下代码:

int main()
{
    while(1)
    {
        cout << "run......." << endl;
        sleep(1);
    }
    return 0;
}

代码是一个死循环,当我们按下Ctrl + C的时候进程会收到一个2号信号SIGINT从而结束进程。

Linux信号解析,Linux,linux,服务器,c++,网络,运维
但是当使用signal函数对2号信号进行自定义捕捉时,这时候再去按下Ctrl + C就不再是执行默认动作结束进程,而是去执行我们的自定义动作,如下代码:

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

int main()
{
    signal(2, handler);
    while(1)
    {
        cout << "run......." << endl;
        sleep(1);
    }
    return 0;
}

在这段代码中,当按下Ctrl + C发送2号信号时,程序会去执行handler方法并打印出捕捉到的信号。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

sigaction函数

sigaction 是一个 POSIX 系统调用,用于检查或修改进程的信号处理行为。与 signal 函数相比,sigaction 提供了更完整和灵活的控制机制来管理信号处理。以下是 sigaction 的函数原型:
Linux信号解析,Linux,linux,服务器,c++,网络,运维
其中参数 signum表示指定要操作的信号。act 是一个指向 struct sigaction 的指针,该结构描述了新的信号处理行为。参数 oldact 是一个指向 struct sigaction 的指针,用于保存之前的信号处理行为。如果不关心之前的行为,可以设置为 NULL。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

struct sigaction 结构包含以下主要字段:

  • sa_handler:指向信号处理函数的指针。
  • sa_sigaction:用于更高级的信号处理,并提供关于信号的更多信息。
  • sa_mask:在处理该信号时要阻塞的其他信号集合。
  • sa_flags:用于指定各种信号处理选项。
  • sa_restorer:此字段已不再使用,但在一些旧的系统中仍然存在。

Linux信号解析,Linux,linux,服务器,c++,网络,运维

sa_flags 可能包括以下选项之一或多个:

  • SA_NOCLDSTOP:如果信号是 SIGCHLD,则在子进程停止或继续时不会产生该信号。
  • SA_NOCLDWAIT:使父进程在其子进程终止时不创建僵尸进程。
  • SA_NODEFER:不将处理的信号自动添加到信号掩码中。
  • SA_ONSTACK:使用为信号专门定义的备用堆栈,如果有的话。
  • SA_RESETHAND:在信号处理程序被调用后,将信号的处理程序重置为默认值。
  • SA_RESTART:使某些被信号中断的系统调用重新启动。
  • SA_SIGINFO:指示信号处理程序应该使用 sa_sigaction 字段而不是 sa_handler。

总的来说,sigaction 提供了一个强大的机制来查看和更改信号处理行为。由于它提供了对信号处理的详细控制,所以它通常被推荐为设置信号处理程序的首选方法。如下代码:

void sighandler(int signo)
{
    cout << "get signo : " << signo << endl;
}
int main()
{
    struct sigaction act, oldact;
    memset(&act, 0, sizeof(act));
    memset(&oldact, 0, sizeof(oldact));
    act.sa_handler = sighandler;
    act.sa_flags = 0;

    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, 2);
    sigaddset(&act.sa_mask, 3);

    sigaction(2, &act, &oldact);
    sigaction(3, &act, &oldact);

    while(1)
    {
        cout << "PID : " << getpid() << endl;
        sleep(1);
    }
    return 0;
}

这段代码设置了信号处理函数 sighandler,然后通过 sigaction 函数为信号2和信号3分别设置了新的信号处理方式,同时设置了信号屏蔽集,以确保在处理这些信号时不会被其他信号中断。然后,程序进入无限循环,输出PID,并持续运行,等待信号的触发。当信号2或3被触发时,将会调用 sighandler 函数来处理它们。
Linux信号解析,Linux,linux,服务器,c++,网络,运维

总结

文章中介绍了Linux中信号的概念、信号的种类以及信号的产生方式进行分析,并对Linux信号的阻塞和捕捉函数进行分析,对函数的参数逐一分析,并提供示例代码供参考。总之,Linux信号是一种重要的进程通信机制,允许进程之间以及操作系统与进程之间进行异步通信,以响应各种事件和异常情况。了解如何正确使用和处理信号对于编写可靠的Linux应用程序至关重要。

码文不易,客官如果觉得文章对你有帮助的话就来一个三连吧👍。

Linux信号解析,Linux,linux,服务器,c++,网络,运维文章来源地址https://www.toymoban.com/news/detail-724063.html

到了这里,关于Linux信号解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux服务器常见运维性能测试(1)综合跑分unixbench、superbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月04日
    浏览(83)
  • [1Panel]开源,现代化,新一代的 Linux 服务器运维管理面板

    本期测评试用一下1Panel这款面板。1Panel是国内飞致云旗下开源产品。整个界面简洁清爽,后端使用GO开发,前端使用VUE的Element-Plus作为UI框架,整个面板的管理都是基于docker的,想法很先进。官方还提供了视频的使用教程,本期为大家按照本专栏的基本内容进行多方面的测评。

    2024年02月07日
    浏览(95)
  • Linux服务器常见运维性能测试(3)CPU测试super_pi、sysbench

    最近需要测试一批服务器的相关硬件性能,以及在常规环境下的硬件运行稳定情况,需要持续拷机测试稳定性。所以找了一些测试用例。本次测试包括在服务器的高低温下性能记录及压力测试,高低电压下性能记录及压力测试,常规环境下CPU满载稳定运行的功率记录。 这个系

    2024年02月02日
    浏览(55)
  • 华为云云耀云服务器L实例评测 | Linux系统宝塔运维部署H5游戏

    本章节内容,我们主要介绍华为云耀服务器L实例,从云服务的优势讲起,然后讲解华为云耀服务器L实例资源面板如何操作,如何使用宝塔运维服务,如何使用运维工具可视化安装nginx,最后部署一个自研的H5的小游戏(6岁的小朋友玩的很开心😁)。 前端的同学如果想把自己

    2024年02月07日
    浏览(58)
  • Linux 中搭建 主从dns域名解析服务器

    作者主页: 点击! Linux专栏:点击! ————前言———— 主从(Master-Slave)DNS架构是一种用于提高DNS系统可靠性和性能的配置方式。 高可用性 :通过配置主从DNS服务器,可以实现DNS服务的高可用性。当主DNS服务器发生故障或不可用时,从DNS服务器可以接管服务,确保域

    2024年03月17日
    浏览(59)
  • Linux设备配置DNS服务器,实现正向解析和反向解析,实现DNS主从服务器同步,实现批量域名正/反向解析

    本文基于Linux上CentOS 7版本配合bind(named)服务进行演示 目录 一.DNS域名服务器原理及作用等介绍 1.DNS简介:  2.原理简单介绍 3.常见域名后缀 4.DNS域名服务器类型 5.DNS服务器的对应关系查询方式 6.具体解析过程 二.bind(named)服务配置文件介绍 1.主配置文件在/etc/named.conf 2.数

    2024年02月08日
    浏览(42)
  • linux并发服务器 —— linux网络编程(七)

    C/S结构 - 客户机/服务器;采用两层结构,服务器负责数据的管理,客户机负责完成与用户的交互;C/S结构中,服务器 - 后台服务,客户机 - 前台功能; 优点 1. 充分发挥客户端PC处理能力,先在客户端处理再提交服务器,响应速度快; 2. 操作界面好看,满足个性化需求; 3.

    2024年02月09日
    浏览(75)
  • Linux - 进阶 NFS服务器 详解网络共享服务器 ( 预备知识)

               N  :  就是 网络 Network          F   :     就是  File  文件         S   :  system          简称为 网络文件系统                 官方   :               NFS 是一种古老的用于UNIX/LINUX主机之间进行文件共享的协议              Network  File  System 网

    2024年02月13日
    浏览(55)
  • 【全面解析】Windows 如何使用 SSH 密钥远程连接 Linux 服务器

    创建密钥 创建 linux 服务器端的终端中执行命令 ssh-keygen ,之后一直按Enter即可,这样会在将在 ~/.ssh/ 路径下生成公钥(id_rsa.pub)和私钥(id_rsa) 注意:也可以在 windows 端生成密钥,只需要保证公钥在服务器端,私钥在本地端即可。 安装 在服务器端 ~/.ssh/ 路径下执行以下命令,在

    2024年02月16日
    浏览(62)
  • 【Linux】配置dns主从服务器,能够实现正常的正反向解析

    ​​​​​​1、首先,在主服务器上配置DNS解析器。打开配置文件 /etc/named.conf ,添加以下内容:   2、创建正向解析区域文件 example.com.zone ,并添加以下内容:   3、创建反向解析区域文件 xx.168.192.zone ,并添加以下内容: 4、在从服务器上进行相同的配置,只需将 type mas

    2024年01月23日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包