Linux系统编程(传统信号和实时信号)

简介: Linux系统编程(传统信号和实时信号)

前言

本篇文章我们来讲解传统信号和实时信号,这里我们将从实际应用给大家讲解。

一、传统信号和实时信号概念

传统信号(Traditional Signals):

传统信号是Unix系统早期定义的信号类型,被称为标准信号(Standard Signals)。

传统信号的范围是1到31,用整数方式表示,例如,SIGINT 是2,SIGALRM 是14。

传统信号的处理方式是异步的,即信号发送后立即触发信号处理程序执行,中断当前进程的正常执行流程。

传统信号的处理程序是函数指针,可以由进程注册自定义的信号处理函数,用于在接收到信号时执行特定的操作。

如果进程没有为某个信号注册处理函数,操作系统将采用默认的处理方式,例如终止进程、忽略信号或者产生核心转储文件。

实时信号(Real-Time Signals):

实时信号是在POSIX.1b标准中引入的一种更高级的信号机制。

实时信号的范围是从实时信号1(SIGRTMIN)到实时信号31(SIGRTMAX),共计64个信号。

实时信号的处理方式可以是同步的或异步的,具体取决于进程设置的信号发送和接收机制。

实时信号的处理程序是函数指针,可以由进程注册自定义的信号处理函数,用于在接收到信号时执行特定的操作。

实时信号的一个重要特点是可以传递一个整数值作为附加数据,这使得实时信号在进程间通信中非常有用。

实时信号相对于传统信号具有更高的灵活性和可靠性,且能够提供更细粒度的信号处理。传统信号在某些情况下可能会发生竞争条件或丢失信号的问题,而实时信号可以帮助解决这些问题。

二、重要函数介绍

1.sigfillset()函数:

int sigfillset(sigset_t *set);

sigfillset()函数将在指定的信号集 set 中设置所有的信号,相当于创建一个包含系统上所有信号的完整集合。信号集 set 会被填充满。

2.sigaddset()函数:

int sigaddset(sigset_t *set, int signum);

sigaddset()函数用于将指定的信号 signum 添加到信号集 set 中。这允许我们将多个信号添加到信号集中,以便后续对其进行操作。

3.sigdelset()函数:

int sigdelset(sigset_t *set, int signum);

sigdelset()函数用于从信号集 set 中删除指定的信号 signum。这个函数可以用来从信号集中删除不再感兴趣的信号。

sigemptyset()函数:

int sigemptyset(sigset_t *set);

sigemptyset()函数用于清空信号集 set,即将所有信号从信号集中删除,使其成为空集。

sigprocmask()函数:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

sigprocmask()函数用于设置进程的信号屏蔽字,控制哪些信号可以传递给进程或阻塞进程对信号的接收。

参数 how 指定了信号屏蔽字的操作方式,可以是以下三个值之一:

SIG_BLOCK:将 set 中的信号添加到进程的信号屏蔽字中。

SIG_UNBLOCK:从进程的信号屏蔽字中移除 set 中的信号。

SIG_SETMASK:设置进程的信号屏蔽字为 set。

参数 set 指定了要添加、删除或设置的信号集。

参数 oldset 是一个可选参数,用于存储之前的信号屏蔽字。

三、实时信号和传统信号被处理的次数

在处理传统信号时,操作系统默认情况下只保留一个挂起的信号。如果在处理信号时,相同类型的信号再次到达进程,且之前的信号尚未处理完毕,则后续到达的信号会被丢弃。

实时信号使用了队列的机制,即使在处理实时信号时,多个相同类型的信号会被排队等待处理。

实时信号有一个优先级的概念,具有更高优先级的实时信号会在低优先级实时信号之前得到处理。

代码实验:

接收端:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
static int g_count = 0;//计数值
static int g_sig = 0;//信号值
void signal_Handle(int sig, siginfo_t* info, void* ucontext)
{
    if(sig = g_sig)
    {
        g_count++;
    }
}
int main(int argc, char** argv)
{
    int i = 0;
    printf("pid :%d\n", getpid());
    sigset_t set = {0};
    g_sig = atoi(argv[1]);
    struct sigaction act = {0};
    act.sa_sigaction = signal_Handle;
    act.sa_flags = SA_RESTART | SA_SIGINFO;
    /* 添加信号屏蔽字 */
    /* 下面信号在信号处理程序执行时会被暂时阻塞 */
    sigaddset(&act.sa_mask, g_sig);
    /* 设置信号的处理行为,设置后40和SIGINT信号将由act里面的信号处理函数处理 */
    sigaction(g_sig, &act, NULL);
    sigaction(SIGINT, &act, NULL);
    /* 屏蔽所有信号 */
    sigfillset(&set);
    sigprocmask(SIG_SETMASK, &set, NULL);
    for(i = 0; i < 15; i++)
    {
        printf("i : %d\n", i);
        sleep(1);
    }
    /* 解除所有屏蔽 */
    sigemptyset(&set);
    sigprocmask(SIG_SETMASK, &set, NULL);    
    printf("g_count = %d\n", g_count);
    return 0;
}

发送端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char** argv)
{
    pid_t pid = atoi(argv[1]);
    int sig = atoi(argv[2]);
    int i = 0;
    union sigval sv = {123456};
    for(i = 0; i < 15000; i++)
    {
        sigqueue(pid, sig, sv);
    }
    raise(SIGINT); 
    return 0;
}

实时信号:

传统信号:

从上面的运行结果可以直接看出来:实时信号不会丢失,而传统信号则会丢失。

总结

本篇文章就讲解到这里,下篇文章见。


相关文章
|
10天前
|
存储 缓存 监控
Linux缓存管理:如何安全地清理系统缓存
在Linux系统中,内存管理至关重要。本文详细介绍了如何安全地清理系统缓存,特别是通过使用`/proc/sys/vm/drop_caches`接口。内容包括清理缓存的原因、步骤、注意事项和最佳实践,帮助你在必要时优化系统性能。
128 78
|
13天前
|
Linux Shell 网络安全
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
本指南介绍如何利用 HTA 文件和 Metasploit 框架进行渗透测试。通过创建反向 shell、生成 HTA 文件、设置 HTTP 服务器和发送文件,最终实现对目标系统的控制。适用于教育目的,需合法授权。
52 9
Kali Linux系统Metasploit框架利用 HTA 文件进行渗透测试实验
|
9天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
62 13
|
1月前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
39 3
|
10天前
|
Ubuntu Linux C++
Win10系统上直接使用linux子系统教程(仅需五步!超简单,快速上手)
本文介绍了如何在Windows 10上安装并使用Linux子系统。首先,通过应用商店安装Windows Terminal和Linux系统(如Ubuntu)。接着,在控制面板中启用“适用于Linux的Windows子系统”并重启电脑。最后,在Windows Terminal中选择安装的Linux系统即可开始使用。文中还提供了注意事项和进一步配置的链接。
28 0
|
1月前
|
Linux
在 Linux 系统中,`find` 命令
在 Linux 系统中,`find` 命令
39 1
|
1月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
93 1
|
21天前
|
存储 Oracle 安全
服务器数据恢复—LINUX系统删除/格式化的数据恢复流程
Linux操作系统是世界上流行的操作系统之一,被广泛用于服务器、个人电脑、移动设备和嵌入式系统。Linux系统下数据被误删除或者误格式化的问题非常普遍。下面北亚企安数据恢复工程师简单聊一下基于linux的文件系统(EXT2/EXT3/EXT4/Reiserfs/Xfs) 下删除或者格式化的数据恢复流程和可行性。
|
7月前
|
NoSQL Unix Linux
Linux下的系统编程——守护进程、线程(十二)
Linux下的系统编程——守护进程、线程(十二)
83 0
Linux下的系统编程——守护进程、线程(十二)
|
7月前
|
存储 Linux Shell
Linux系统编程(守护进程)
Linux系统编程(守护进程)
84 0