WordPress打开速度不稳定,郑州seo竞价,深圳外贸网站建设设计公司,wordpress同步谷歌博客信号 在Linux中什么是信号信号的产生方式硬件产生的信号软件产生的信号异常产生的信号 进程对信号的处理信号的保存信号方法更改函数signal信号处理的更改恢复默认信号忽略 信号的管理信号集 sigset_t对信号集的操作 信号的捕捉过程 在Linux中什么是信号
在 Linux 系统中… 信号 在Linux中什么是信号信号的产生方式硬件产生的信号软件产生的信号异常产生的信号 进程对信号的处理信号的保存信号方法更改函数signal信号处理的更改恢复默认信号忽略 信号的管理信号集 sigset_t对信号集的操作 信号的捕捉过程 在Linux中什么是信号
在 Linux 系统中信号是一种进程间通信的基本机制用于通知进程发生了某种事件。 信号是一种软件中断用于通知进程发生了某种事件。 这些事件可能包括硬件异常、用户输入、系统调用请求等。信号是异步发生的即进程无法预测信号何时发生但当信号发生时系统会将信号发送给相应的进程。
在Linux中,信号一般被分为三大类:可以在bash使用kill -l 命令直接产看 标准信号Standard Signals由内核或进程向进程发送的信号,上图中的1-31号新号即为标准信号 实时信号Real-time Signals在标准信号的基础上引入了实时性概念允许信号排队和按优先级传递,上图中的34-64即为实时信号 自定义信号User-defined Signals用户可以定义自己的信号类型用于特定应用或通信需求。
信号的产生方式
无论信号有多少种产生方式,永远只能让OS向目标进程发送
硬件产生的信号
硬件产生的信号是由硬件设备或操作系统内核生成的用于通知进程发生了某种事件。例如当我们按下键盘上的^C键时硬件会生成中断信号SIGINT来通知操作系统然后操作系统将其传递给相应的进程
软件产生的信号
软件产生的信号是由进程自身或其他进程通过系统调用如 kill )发送给目标进程的。这种方式允许进程之间进行通信和协作例如向目标进程发送中断信号SIGINT以请求其终止执行:kill -9 pidnum
异常产生的信号
异常产生的信号是由硬件或操作系统检测到的异常事件引起的。例如当进程执行非法指令、访问越界内存或发生浮点数异常时硬件或操作系统会生成相应的信号如 SIGILL、SIGSEGV、SIGFPE来通知进程发生了异常情况。
进程对信号的处理
信号的保存
每个进程的PCB中都有一张自己的函数指针数组,一般被称为信号处理函数表,这个数组中的每个元素对应一个特定信号的处理函数。
当进程接收到信号时操作系统会根据进程的PCB中的信号处理函数表找到对应的处理函数并执行相应的逻辑。
以下是对信号处理的几个概念:
信号递达:实际信号的处理动作,一般有三种:默认,忽略,自定义信号未决(pending):信号从产生到递达之间的状态,即在信号的位图中时,一斤产生但未被处理时的状态信号阻塞(block):信号时允许被阻塞的,信号产生了,但暂时不进行递达的信号就是阻塞信号
因此操作系统会在进程PCB中创建三个表,用于对信号的状态进行记录, 其中,block表记录的是对应位置信号是否被屏蔽 pending表记录的是对应位置信号是否未决 handler表记录的事对应位置信号的执行方式
信号方法更改函数signal
信号处理的更改
在Linux中,信号处理函数 (signal) 是一种用来处理异步事件的方法。 信号是一个软件中断通常由操作系统生成用来通知程序某个事件已经发生例如非法操作、外部中断、定时器溢出等。
原型如下:
void (*signal(int signum, void (*handler)(int)))(int);两个参数:
signum表示要设置的信号编号handler表示要设置的信号处理函数可以是一个函数指针一般来说是我们自己写的一个函数,将signum所表示的信号重新实现
注意事项
可重入性信号处理函数应该是可重入的即它们应该避免使用全局状态和执行非原子操作。限制在信号处理函数中只有少数几个函数是安全可调用的通常称为异步信全函数。例如大多数系统调用和库函数都不应该在信号处理函数中调用。
举例:这是一个将2号信号进行更改,原本应该执行的功能被我修改成了handler函数内的内容
#includeiostream
#includesignal.h
#includeunistd.hvoid handler(int signo)
{std::cout 获得一个 signo 号信号 std::endl;exit(1);
}int main()
{signal(2,handler);return 0;
}恢复默认
如果在开发过程中,忘记了自己之前对某个信号的执行更改,可以将signal函数的第二个参数传入宏:SIG_DFL来使得信号执行它默认的功能
signal(2,SIG_DFL);信号忽略
在程序开发中,如果想要忽略某个信号,可以直接将signal函数的第二个参数传参宏:SIG_IGN
signal(2,SIG_IGN);信号的管理
为了高效地处理多个信号因此要先描述,再组织 , Linux提供了信号集的概念使得可以将多个信号组合在一起进行处理。
信号集 sigset_t
sigset_t是一个用于表示信号集的数据类型它通常定义在signal.h头文件中。 原型:
typedef struct sigset_t {unsigned long sig[_NSIG / sizeof(long)];
} sigset_t;其中_NSIG是一个宏表示系统中定义的信号总数。sigset_t类型的信号集用于保存一个或多个信号的集合可以通过位运算来操控信号集。
对信号集的操作
要创建一个空的信号集可以使用以下代码
sigset_t empty_set;
sigemptyset(empty_set);这样就有了一个新的信号集,这将清除empty_set中的所有信号位使其成为一个空集。
创建一个全满的信号集:
sigset_t full_set;
sigfillset(full_set);这样就可以创建一个全满的信号集,并且将full_set中的所有信号位设置为1表示设置了所有可能的信号。
设置或查询进程的信号前景,就好像设置权限掩码一样,对信号这些信号在进程处于等待状态如在 select、poll、epoll_wait 等系统调用中时会被优先处理:
void sigprocmask(int how, const sigset_t *set, sigset_t *oldset);其中how参数表示拷贝的方式可以是SIG_BLOCK、SIG_UNBLOCK或SIG_SETMASK。set参数指向要拷贝的信号集oldset参数用于接收旧的信号集。
添加信号集:
void sigaddset(sigset_t *set, int signum);该函数将signum信号的位添加到set信号集中。
清除信号集:
void sigdelset(sigset_t *set, int signum);该函数将signum信号的位从set信号集中删除。
检查信号是否存在于信号集中:
int sigismember(const sigset_t *set, int signum);返回 1如果指定的信号 signum 在信号集 set 中。 返回 0如果指定的信号 signum 不在信号集 set 中。 返回 -1如果发生错误例如指定的信号编号无效并且设置全局变量 errno
查询当前进程等待处理的信号集合,也就是查询处于pending状态的信号集合.这个函数可以帮助进程了解有哪些信号已经被生成但尚未被处理。
int sigpending(sigset_t *set);当 sigpending 函数被调用时它会将当前进程的信号等待集合即那些已经被生成但尚未被处理或阻塞的信号复制到 set 指向的 sigset_t 变量中。这样进程就可以通过检查 set 中的信号位来确定有哪些信号需要处理。
下面是一个代码示例我们首先使用 sigprocmask 函数屏蔽了 SIGINT 信号。然后我们让进程睡眠5秒钟以便有足够的时间让用户按下 CtrlC。在睡眠之后我们调用 sigpending 函数来查询当前进程等待的信号。如果 SIGINT 信号在等待队列中我们将打印出相应的信息。最后我们使用 sigprocmask 函数恢复到旧的信号掩码以便进程可以正常处理信号。
#include signal.h
#include unistd.h
#include stdio.hint main() {sigset_t pending_mask, empty_mask, old_mask;// 创建一个信号集合用于存储 SIGINTsigemptyset(empty_mask);sigaddset(empty_mask, SIGINT); // 添加 SIGINT 到屏蔽集合// 阻止 SIGINT 信号if (sigprocmask(SIG_BLOCK, empty_mask, old_mask) -1) {perror(sigprocmask);return 1;}printf(SIGINT 信号已被屏蔽现在我将进入睡眠状态。\n);// 睡眠一段时间以便有机会生成 SIGINT 信号sleep(5);// 查询当前进程等待的信号if (sigpending(pending_mask) -1) {perror(sigpending);return 1;}// 打印等待的信号if (sigismember(pending_mask, SIGINT)) {printf(SIGINT 信号正在等待处理。\n);} else {printf(没有信号在等待处理。\n);}// 恢复旧的信号掩码if (sigprocmask(SIG_SETMASK, old_mask, NULL) -1) {perror(sigprocmask);return 1;}return 0;
}
信号的捕捉过程
如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。 但是自定义信号处理函数是我们自己写的,是存在于用户空间的,因此这里涉及到一个用户到内核的转换问题,因为用户并不具有所有的操作权限,下面的图片可以很清楚的表达出信号捕捉过程中用户和内核态的转化过程 图片来自必应搜索