【IPC 通信】信号处理接口 Signal API(1)
收发信号思想是 Linux 程序设计特性之一,一个信号可以认为是一种软中断,通过用来向进程通知异步事件。
本文讲述的 信号处理内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解信号编程。
信号概述
遵循 POSIX.1,特别说明除外
1.描述
Linux 支持 POSIX 可靠信号(我们成为标准信号),也支持 POSIX 实时信号。
信号处置方法
每个信号都有一个定义如何处理信号的处置方法。
下面列表中 “行为” 列定义了每个信号的默认处置行为:
信号 | 默认行为 |
Term | 默认行为是终止进程 |
Ign | 默认行为是忽略这个信号 |
Core | 默认行为是终止进程并转储内核(dump core) |
Stop | 默认行为是停止进程 |
Cont | 默认行为是在进程停止后继续执行该进程 |
进程可以通过 sigaction(2) 或者 signal(2) 接口修改信号的处置方法。(后者在建立信号处理函数时移植性差一些,参考 signal(2) 获得详细信息。)通过这些系统调用,在信号发生时,进程可以选择以下行为处理信号:
- 使用默认行为
- 过略信号
- 使用信号处理函数(signal handler)捕获信号
- 使用用户自定义的函数
默认情况下,信号处理函数是在普通进程栈上调用的,不过也可以设置它使用其他可选的栈,参考 sigaltstack(2) 查看一些关于如何使用以及这样做有哪些好处的讨论。
信号处置是每个进程的属性:在多线程应用中,信号处置函数对于所有线程都是一样的。
通过 fork(2) 创建的子进程会复制一份父进程的信号处置方法,在 execve(2) 执行的过程中,进程想要处理的信号处置方法会被设置为默认值,而处置方法为忽略的信号保持不变。
发送信号
下面系统调用和库函数提供了调用者发送信号的相关接口:
raise(3)
向调用线程发送一个信号
kill(2)
向指定进程、指定进程组下的所有进程、系统的所有进程发送信号
pidfd_send_signal(2)
向 PID 文件描述符指定的进程发送一个信号
killpg(3)
向指定进程组所有成员发送一个信号
pthread_kill(3)
向调用者所在进程中其他 pthread 线程发送一个信号
tgkill(2)
向指定进程中的特定线程发送一个信号(这是用来实现 pthread_kill(3) 的系统调用)
sigqueue(3)
向指定进程发送一个福袋数据的实时信号
等待捕捉信号
下面系统调用会暂停当前调用线程直至捕捉到一个信号(或者无法处理的信号终止该进程):
pause(2)
暂停直至捕捉到一个信号
sigsuspend(2)
临时修改信号屏蔽值并暂停执行直至捕捉到任意未屏蔽的信号
同步接收信号
除了通过信号处理函数异步处理信号,我们还可以通过同步接收信号,也就是说程序会阻塞运行直至接收到信号,同时也是在这一点内核会返回调用者一些关于信号的信息。通常有两种方式实现同步信号接收:
- sigwaitinfo(2)、sigtimedwait(2)、sigwait(3) 都会阻塞执行直到收到指定集合里的信号发生,每个调用都会返回接收到信号的信息。
- signalfd(2) 会返回一个用于读取关于接收信号的文件描述符,每次对文件描述符的 read(2)调用都会一直阻塞直到通过 signalfd(2) 指定的信号集合里的任何一个信号发生。read(2) 返回的 buffer 里包含关于该信号的描述结构。
信号屏蔽和等待信号
一个信号是可以被屏蔽的,也就是说只有在打开屏蔽后才会得到分发。其实我们上面说的信号发生更确切的说是信号分发到了进程。那么信号在生成和被分发之前的状态我们成为等待(pending)。
一个进程中的每个线程都有一个独立的信号屏蔽(signal mask),或者也可以称为掩码,它只是了线程当前屏蔽掉的信号集合。线程可以通过 pthread_sigmask(3) 来操作信号掩码,在传统的单线程应用中可以通过 sigprocmask(2) 来操作信号掩码。
通过 fork(2) 创建的子进程复制一份父进程的信号掩码,信号掩码在整个 execve(2) 过程中会一直保留。
一个信号可以是发给进程的也可以是发给线程的。发给进程的信号通常是由内核产生的而不是由特定硬件异常产生的,通常是由类似 kill(2) 或者 sigqueue(3) 产生的。而发给线程的信号可能是因为执行了一些特定机器语言指令导致硬件异常(比如非法内存访问的 SIGSEGV 信号,或者数学错误的 SIGFPE)导致的,或者是线程执行了特定接口,比如 tgkill(2) 或者 pthread_kill(3)。
发给进程的信号是可以被分发到进程内任何没有屏蔽整个信号的线程的。如果不止一个线程没有屏蔽该信号,那么内核会随便选一个线程分发该信号。
线程可以通过 sigpending(2) 接口来获得当前处于等待状态的信号集,信号集是一个进程等待信号和线程等待信号的共用体。
通过 fork(2) 创建的进程初始化为控的等待信号集,在整个 execve(2) 过程中,该等待信号集保持不变。
信号处理函数执行
在每次内核模式到用户模式的切换时(也就是一个系统调用返回或者调用一个线程到 CPU 上运行),内核都会检查该进程建立信号处理函数的信号的非屏蔽信号的等待状态。如果有这样的信号存在,那么就会进行以下几步:
(1)内核会在执行信号处理函数前做一些准备工作:
(1.1)信号从等待信号集合中移除
(1.2)如果信号处理函数是通过 sigaction(2) 安装并指定了 SA_ONSTACK 标记,集线程定义了一个候补信号栈(使用 sigaltstack(2)),那么内核就会安装这个栈
(1.3)信号相关的一些上下文片段会被封装到栈上的特定帧里,保存的信息包括:
a)程序计数寄存(也就是处理函数退出后主程序要执行的下一条指令)
b)一些为恢复被打断程序运行的架构相关的寄存器
c)线程当前的信号掩码
d)线程的备用信号栈设置
(如果信号是通过 sigaction(2) SA_SIGINFO 标记安装的,那么上述信息是可以通过 ucontex_t 对象获取的,这个对象由信号处理函数的第三个参数指定。
(2)内核在栈上为信号处理函数构建一个栈帧,内核设置线程的 PC 为信号处理函数的第一条指令,并配置信号处理函数的返回地址到一个称为信号蹦床的用户空间代码片段(在 sigreturn(2) 中有描述)。
(3)内核将控制权返还给用户空间,这样就会从信号处理函数的开始执行。
(4)当信号处理函数返回时,控制器交给信号蹦床代码。
(5)信号蹦床调用 sigreturn(2),sigreturn(2) 是一个系统调用,用来使用步骤 1 中创建的栈帧来恢复信号发生之前的线程状态。信号掩码和备用信号栈也会在这个过程中得到恢复。在完成 sigreturn(2) 调用后,内核将控制权交给用户空间,线程会接着从被信号打断的点继续执行。
值得注意的是,如果信号处理函数不返回(比如通过 siglongjmp(3) 将控制权交给了处理函数外或者处理函数通过 execve(2) 执行了一个程序),那么最后的步骤就不会执行。这种情况下,程序设计者应该特别注意,如果想要恢复在进入信号处理函数时屏蔽掉的信号的话,就必须自己恢复这些信号掩码(使用 sigprocmask(2))。(注意:siglongjmp(3) 可能恢复信号掩码,但是这个要依赖于 sigsetjmp(3) 的 savesigs 值。
从内核的角度来看,执行信号处理函数和执行其他任何用户空间代码没有什么区别,也就是说内核并不会记录线程当前是否在执行信号处理函数。所有的状态都被保存到了用户空间寄存器和用户空间栈里了,所以信号处理函数的嵌套深度完全取决于用户栈大小(以及合理的软件设计)。
标准信号
Linux 支持的标准信号入下表所示。表中第二列标明了信号出现的规范:“P1990” 表示信号是在原先的 POSIX.1-1990 标准中描述的;“P2001” 表示信号是在 SUSv2 和 POSIX.1-2001 中添加的。
信号 | 标准 | 行为 | 备注 |
SIGABRT | P1990 | Core | abort(3) 的终止信号 |
SIGALRM | P1990 | Term | alarm(2) 的定时器信号 |
SIGBUS | P2001 | Core | 总线错误(错误内存访问) |
SIGCHLD | P1990 | Ign | 子进程停止或者终止了 |
SIGCLD | - | Ign | 同 SIGCHLD |
SIGCONT | P1990 | Cont | 如果停止了,就继续执行 |
SIGEMT | - | Term | 模拟器陷入 |
SIGFPE | P1990 | Core | 浮点异常 |
SIGHUP | P1990 | Term | 控制终端上检测到挂机或者控制进程死掉了 |
SIGILL | P1990 | Core | 非法指令 |
SIGINFO | - | 同 SIGPWR | |
SIGINT | P1990 | Term | 键盘中断 |
SIGIO | - | Term | I/O 现在可用(4.2 BSD) |
SIGIOT | - | Core | IOT 陷入,同 SIGABRT |
SIGKILL | P1990 | Term | 杀死信号 |
SIGLOST | - | Term | 文件锁丢失(不用了) |
SIGPIPE | P1990 | Term | 破坏的管道:写一个没有读者的管道,参考 pipe(7) |
SIGPOLL | P2001 | Term | 可查询事件(Sys V),同 SIGIO |
SIGPROF | P2001 | Term | 分析定时器超时 |
SIGPWR | - | Term | 电源失效(System V) |
SIGQUIT | P1990 | Core | 键盘上的退出 |
SIGSEGV | P1990 | Core | 无效的内存引用 |
SIGSTKFLT | - | Term | 协处理器栈错误(不用了) |
SIGSTOP | P1990 | Stop | 停止进程 |
SIGTSTP | P1990 | Stop | 终端输入的停止信号 |
SIGSYS | P2001 | Core | 非法的系统调用(SVr4),参考 seccomp() |
SIGTERM | P1990 | Term | 终止信号 |
SIGTRAP | P2001 | Core | 追踪/断电 陷入 |
SIGTTIN | P1990 | Stop | 后台进程终端输入 |
SIGTTOU | P1990 | Stop | 后台进程终端输出 |
SIGUNUSED | - | Core | 同 SIGSYS |
SIGURG | P2001 | Ign | 套接字上的紧急事件(4.2 BSD) |
SIGUSR1 | P1990 | Term | 用户定义的信号 1 |
SIGUSR2 | P1990 | Term | 用户定义的信号 2 |
SIGVTALRM | P2001 | Term | 虚拟定时器时钟(4.2 BSD) |
SIGXCPU | P2001 | Core | 超过 CPU 时间限制,参考 setrlimit(2) |
SIGXFSZ | P2001 | Core | 文件大小超过限制(4.2 BSD),参考 setrlimit(2) |
SIGWINCH | - | Ign | 窗口大小重设信号(4.3 BSD,Sun) |
SIGKILL 和 SIGSTOP 不能被捕捉或者忽略。
Linux 2.2 前,SIGSYS/SIGXCPU/SIGXFSZ(除了 SPARC 和 MIPS 架构)以及 SIGBUS 的默认行为是终止进程(并没有内核转储)。(在一些 UNIX 的系统上,SIGXCPU 和 SIGXFSZ 的默认行为也是不转储的终止。)Linux 2.4 遵循 POSIX.1-2001 对这些信号的要求,会终止进程并进行内核转储。
SIGEMT 并没有在 POSIX.1-2001 中描述,但是至少出现在了大多数 UNIX 系统中,并且其默认行为是终止进程并内核转储。
SIGPWR 也没有在 POSIX.1-2001 中描述,它在起源的一些 UNIX 系统中的默认行为是忽略。
SIGIO 也一样,在一些 UNIX 系统上的默认行为是忽略。
标准信号的排队和分发语义
如果多个标准信号正在等待某个进程,那么信号的顺序并没有指定。
标准信号没有排队,如果一个标准信号的多个实例在信号屏蔽期间到达,那么只有一个信号会被设置为等待状态(信号只能在其取消屏蔽后会分发给进程)。如果一个信号已经在等待,和这个信号关联的 siginfo_t 结构(参考 sigaction(2))并不会被后面的同一信号的其他实例覆盖。因此,进程会接收到第一个达到的信号实例。
标准信号编码
下表列出了各个标准信号的号码。在表中我们可以看出,一些信号在不同架构上的号码是不一样的。- 表示对应架构上没有该信号。
信号 | x86/ARM 以及其他大多数 | Alpha/SPARC | MIPS | PARISC | 备注 |
SIGHUP | 1 | 1 | 1 | 1 | |
SIGINT | 2 | 2 | 2 | 2 | |
SIGQUIT | 3 | 3 | 3 | 3 | |
SIGILL | 4 | 4 | 4 | 4 | |
SIGTRAP | 5 | 5 | 5 | 5 | |
SIGABRT | 6 | 6 | 6 | 6 | |
SIGIOT | 6 | 6 | 6 | 6 | |
SIGBUS | 7 | 10 | 10 | 10 | |
SIGEMT | - | 7 | 7 | - | |
SIGFPE | 8 | 8 | 8 | 9 | |
SIGKILL | 9 | 9 | 9 | 9 | |
SIGUSR1 | 10 | 30 | 16 | 16 | |
SIGSEGV | 11 | 11 | 11 | 11 | |
SIGUSR2 | 12 | 31 | 17 | 17 | |
SIGPIPE | 13 | 13 | 13 | 13 | |
SIGALRM | 14 | 14 | 14 | 14 | |
SIGTERM | 15 | 15 | 15 | 15 | |
SIGSTKFLT | 16 | - | - | - | |
SIGCHLD | 17 | 20 | 18 | 18 | |
SIGCLD | - | - | 18 | - | |
SIGCONT | 18 | 19 | 25 | 26 | |
SIGSTOP | 19 | 17 | 23 | 24 | |
SIGTSTP | 20 | 18 | 24 | 25 | |
SIGTTIN | 21 | 21 | 26 | 27 | |
SIGTTOU | 22 | 22 | 27 | 28 | |
SIGURG | 23 | 16 | 21 | 29 | |
SIGXCPU | 24 | 24 | 30 | 12 | |
SIGXFSZ | 25 | 25 | 31 | 30 | |
SIGVTVLRM | 26 | 26 | 28 | 20 | |
SIGPROF | 27 | 27 | 29 | 21 | |
SIGWINCH | 28 | 28 | 20 | 23 | |
SIGIO | 29 | 23 | 22 | 22 | |
SIGPOLL | |||||
SIGPWR | 30 | 29/- | 19 | 19 | |
SIGINFO | - | 29/- | - | - | |
SIGLOST | - | - | - | - | |
SIGSYS | 31 | 12 | 12 | 31 | |
SIGUNUSED | 31 | - | - | 31 |
注意:
- 如果有定义,那么 SIGUNUSED 和 SIGSYS 含义相同。但是 glibc 2.26 后,不管是什么架构上都没有 SIGUNUSED 定义了。
- Alpha 上 29 号信号是 SIGINFO/SIGPWR(含义相同),而在 SPARC 上是 SIGLOST 信号。
实时信号
从 Linux 2.2 开始,Linux 开始支持 POSIX.1b 实时扩展定义的实时信号(目前包含在 POSIX.1-2001 中)。支持的实时信号范围由宏 SIGRTMIN 和 SIGRTMAX 定义,POSIX.1-2001 要求至少支持 _POSIX_RTSIG_MAX(8) 个实时信号。
Linux 内核支持 33 个不同的实时信号,号码是从 32 到 64。然而,glibc 的 POSIX 线程使用了 2个(对于 NPTL)或者 3 个(对于 LinuxThreads)实时信号(参考 pthreads(7)),所以调整 SIGRTMIN 为 34 或者 35。正因为实时信号的范围随着 glibc 多线程的实现不同而不同(这个在运行时会根据内核和 glibc 而定),并且事实上也会根据不同 UNIX 系统不同而不同,所以程序不应该使用硬编码值指定实时信号,而应该使用 SIGMIN+n 这种形式来引用实时信号,并且需要在运行时检查其是否超过了 SIGRTMAX。
和标准信号不同,实时信号没有预定义的含义,即整个实时信号集都可以被应用使用。
实时信号的默认处理行为是终止接收进程。
实时信号通过以下方式来区分:
- 实时信号的多个实例可以排队,这个和标准信号完全相反
- 如果信号由 sigqueque(3) 发送,可以附带一个这个数值(可以是整数或者指针)。接收进程通过sigaction(2) 的 SA_SIGINFO 来建立该信号的处理函数,然后就可以通过处理函数第二个参数的 siginfo_t 结构的 si_value 来获得这个数值。并且可以通过结构的 si_pid 和 si_uid 可以获得发送信号进程的进程 ID 和用户 ID。
- 实时信号的分发的顺序是能够得到保证的。同一个类型实时信号的多个实例会按照它们实际的发送顺序分发。多个信号发送到同一个进程,那么会从号码最小的信号依次分发(即号码越小,优先级越高。)相反,多个标准信号处于等待状态,先分发谁是没有定义的。
如果一个进程有标准信号和实时信号一起处在等待状态,那么 POSIX 并没有指定应该先发送谁。Linux 以及很多其他实现会优先标准信号。
根据 POSIX 规定,系统实现应该最少支持 _POSIX_SIGQUEQUE_MAX (32) 个实时信号等待,然而 Linux 却采用了不同的方式。Linux 2.6.7 之前,只暴漏了对所有进程总共实时信号数的系统级限制,这个限制可以通过(需要特权)/proc/sys/kernel/rtsig-max 文件查看或者修改。可以通过 /proce/sys/kernel/rtsig-nr 查看当前有多少个实时信号正在等待处理。在 Linux 2.6.8,/proc 接口被 RLIMIT_SIGPENDING 资源限制取代,这是一个每个用户下排队信号的限制,可以参考 setrlimit(2)。
实时信号要求信号集结构(sigset_t)的长度从 32位变为 64 位。所以各个系统调用被新的系统调用取代,下面是接口的对照:
Linux 2.0 and earlier Linux 2.2 and latersigaction(2) rt_sigaction(2)sigpending(2) rt_sigpending(2)sigprocmask(2) rt_sigprocmask(2)sigreturn(2) rt_sigreturn(2)sigsuspend(2) rt_sigsuspend(2)sigtimedwait(2) rt_sigtimedwait(2)
信号处理函数打断系统调用和库函数调用
如果在系统调用或者函数调用过程中调用信号处理函数,那么:
- 系统调用会在信号处理函数返回后自动重启,或者
- 调用失败并返回 EINTR
至于采用哪种行为主要取决于具体的接口以及建立信号处理函数时是否使用了 SA_RESTART 标记(参考 sigaction(2))。具体行为会随着不同的 UNIX 而不同,下面主要描述 Linux 平台上的相关细节。
如果如下接口中的一个阻塞调用被信号处理函数自动打断,那么如果使用了 SA_RESTART 标记,那么调用会在处理函数返回后自动重启,或者会返回 EINTR 错误:
- 慢速设备上的 read(2)/readv(2)/write(2)/writev(2)/ioctl(2) 调用。慢速设备指的是 I/O 调用可能会无限期阻塞的设备,比如终端、管道以及套接字。如果这些慢速设备上的 I/O 调用在被打断时已经传输了一些数据,那么调用会返回成功状态(通常情况下时传输的字节数)。注意根据这个定义本地磁盘不是慢速设备,磁盘上的 I/O 操作不会被信号打断。
- open(2),如果它可能阻塞(比如当打开一个 FIFO,参考 fifo(7))
- wait(2)/wait3(2)/wait4(2)/waitid(2)/waipid(2)
- 套接字接口:accept(2)/connect(2)/recv(2)/recvfrom(2)/recvmmsg(2)/recvmsg(2)/send(2)/sendto(2)/sendmsg(2),除非套接字设置了超时(下面会提到)
- 文件锁定接口:flock(2) 以及 fcntl(2) 的 F_SETLKW/F_OFD_SETLKW 操作
- POSIX 消息队列接口:mq_receive(3)/mq_timedreceive(3)/mq_send(3)/mq_timedsend(3)
- futex(2) FUTEX_WAIT(Linux 2.6.22 后,之前总是会返回 EINTR)
- getrandom(2)
- pthread_mutex_lock(3)/pthread_cond_wait 以及相关 APIs
- futex(2) FUTEX_WAIT_BITSET
- POSIX 信号量语义接口:wem_wait(3)/sem_timedwait(3)(Linux 2.6.22 后,之前会失败返回 EINTR)
- 从 inotify(7) 文件描述符的 read(2)(从 Linux 3.8 后,之前会返回 EINTR)
下面接口在被信号处理函数打断时不会重启,无论是否设置 SA_RESTART 标记,会返回 EINTR 错误:
- 使用 setsockopt(2) 设置了超时(SO_RCVTIMEO)的输入套接字接口:accept(2)/recv(2)/recvfrom(2)/recvmmsg(2)(同时有非空 timeout 参数,以及 recvmsg(2)
- 使用 setsockopt(2) 设置了超时(SO_RCVTIMEO)的输出套接字接口:connect(2)/send(2)/sendto(2)/sendmsg(2)
- 等待信号的接口:pause(2)/sigsuspend(2)/sigtimedwait(2)/sigwaitinfo(2)
- 文件描述符多路复用接口:epoll_wait(2)/epoll_pwait(2)/poll(2)/select(2)/pselect(2)
- System V IPC 接口:msgrcv(2)/msgsnd(2)/semop(2)/semtimedop(2)
- 睡眠接口:clock_nanosleep(2)/nanosleep(2)/usleep(3)
- io_getevents(2)
usleep(3) 在被信号处理函数打断时不会重启,会成功返回睡眠剩余时间的秒数。
在一些情况下,sseccomp(2) 用户空间通知特性会导致通过 SA_RESTART 配置不会重启的系统调用重启,具体可以参考 seccomp_unotify(2)。
停止信号打断系统调用和库函数调用
在 Linux 上,即使没有信号处理函数,一些阻塞接口也可能在收到停止信号停止在收到 SIGCONT 信号恢复时返回 EINTR 错误。这个行为并没有受到 POSIX.1 的限制,并不会在其他系统上发生。
Linux 上会显示出这种行为的接口有:
- 使用 setsockopt(2) 设置了超时(SO_RCVTIMEO)的输入套接字接口:accept(2)/recv(2)/recvfrom(2)/recvmmsg(2)(同时有非空 timeout 参数,以及 recvmsg(2)
- 使用 setsockopt(2) 设置了超时(SO_RCVTIMEO)的输出套接字接口:connect(2)/send(2)/sendto(2)/sendmsg(2)
- epoll_wait(2)/epoll_pwait(2)
- semop(2)/semtimedop(2)
- sigtimedwait(2)/gitwaitinfo(2)
- Linux 3.7 前从 inotify(7) 文件描述符读取的 read(2)
- Linux 2.6.21 前 futex(2) FUTEX_WAIT/sem_timedwait(3)/sem_wait(3)
- Linux 2.6.8 前 msgrcv(2)/msgsnd(2)
- Linux 2.4 前 nanosleep(2)
2.注意
对于安全的异步信号函数,可以参考 sigal-safety(7)。
/proc/pid/task/tid/status 文件包含了一些用于显示一个线程正处于阻塞(SigBlk)、捕获(SigCgt)或者忽略(SigIgn)的字段。(进程中所有线程的阻塞和忽略信号相同。)其他字段展示了发给线程(SigPnd)或者进程(ShdPnd)的等待信号。/proc/pid/status 展示了关于主线程的信息。参考 proc(5) 获得详细信息。
3.BUGS
一共有 6 中关于硬件异常的信号:SIGBUS/SIGEMT/SIGFPE/SIGILL/SIGSEGV/SIGTRAP。至于这些信号哪些会真的分发,文档中并没有给出描述,并且也并不总是有效。
比如,一个架构非法地址访问可能导致 SIGSEGV,但是在其他架构上可能会导致 SIGBUS,反过来也是一样。
再比如,使用 x86 的 int 指令携带了禁止参数(除了 3 和 128 的任意数)会导致 SIGSEGV,尽管这时发送 SIGILL 会更合适,因为它是在向内核报告禁止操作。
4.例程
下面是一个 sigaction 的信号处理例程。
#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>voidhandler(int signo, siginfo_t *info, void *context){struct sigaction oldact;if (sigaction(SIGSEGV, NULL, &oldact) == -1|| (oldact.sa_flags & SA_UNSUPPORTED)|| !(oldact.sa_flags & SA_EXPOSE_TAGBITS)){_exit(EXIT_FAILURE);}_exit(EXIT_SUCCESS);}intmain(void){struct sigaction act = { 0 };act.sa_flags = SA_SIGINFO | SA_UNSUPPORTED | SA_EXPOSE_TAGBITS;act.sa_sigaction = &handler;if (sigaction(SIGSEGV, &act, NULL) == -1) {perror("sigaction");exit(EXIT_FAILURE);}raise(SIGSEGV);}
相关文章:
【IPC 通信】信号处理接口 Signal API(1)
收发信号思想是 Linux 程序设计特性之一,一个信号可以认为是一种软中断,通过用来向进程通知异步事件。 本文讲述的 信号处理内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解信号编程。 信号概述 遵循 POSIX.1,…...

使用GDIView排查GDI对象泄漏导致的程序UI界面绘制异常问题
目录 1、问题说明 2、初步分析 3、查看任务管理器,并使用GDIView工具分析 4、GDIView可能对Win10兼容性不好,显示的GDI对象个数不太准确 5、采用历史版本比对法,确定初次出现问题的时间点,并查看前一天的代码修改记录 6、将…...
蓝桥等考Python组别一级001
第一部分:选择题 1、Python L1 (15分) 下面哪个不是Python的编程环境?( ) Python在线编程IDLEPyCharmScratch正确答案:D 2、Python L1(15分) 世界上第一台通用电子计算机ENIAC是在( )诞生的。 美国英国日本德国正确答案:A 3、Python L1(20分) 关于P…...

Unity之Hololens2开发 如何接入的MRTK OpenXR Plugin
一.前言 什么是Hololens? Hololens是由微软开发的一款混合现实头戴式设备,它将虚拟内容与现实世界相结合,为用户提供了沉浸式的AR体验。Hololens通过内置的传感器和摄像头,能够感知用户的环境,并在用户的视野中显示虚拟对象。这使得用户可以与虚拟内容进行互动,将数字信…...

Ubuntu系统Linux内核安装和使用
安装: 检查树莓派Linux版本,我的是6.1 uname -r 内核下载链接: Raspberry Pi GitHub 找对应版本下载 导入之后,解压安装即可 unzip linux-rpi-6.1.y.zip 其他内容 treee 指令安装 sudo apt-get install tree 使用这…...
数学术语之源——群同态的“核(kernel)”
1. “kernel”这个术语在群论中的起源 Ivar Fredholm 在 1903 年的第27期Acta Math 数学学报发表的一篇关于“积分方程(INTEGRAL EQUATIONS)”的著名论文(“关于一类函数方程(Sur une classe des quations fonctionnelles)”)中使用了法语“noyau(核)”(365-390页)。 David …...

defcon-quals 2023 crackme.tscript.dso wp
将dso文件放到data/ExampleModule目录下,编辑ExampleModule.tscript文件 function ExampleModule::onCreate(%this) { trace(true); exec("./crackme"); __main("aaaaaaaa"); quit(); } 然后点击主目录下的Torque3D-debug.bat就可以在生成的c…...

前端开发 vs. 后端开发:编程之路的选择
文章目录 前端开发:用户界面的创造者1. HTML/CSS/JavaScript:2. 用户体验设计:3. 响应式设计:4. 前端框架: 后端开发:数据和逻辑的构建者1. 服务器端编程:2. 数据库:3. 安全性&#…...
算法练习4——删除有序数组中的重复项 II
LeetCode 80 删除有序数组中的重复项 II 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 …...

【C++进阶(六)】STL大法--栈和队列深度剖析优先级队列适配器原理
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:C从入门到精通⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你学习C 🔝🔝 栈和队列 1. 前言2. 栈和队列的接口函数熟悉3. …...

linux opensuse使用mtk烧录工具flashtool
环境 linux发行版:opensuse leap 15.5 工具:SP_Flash_Tool_Selector_exe_Linux_v1.2316.00.100.rar 或其他版本 目标:mtk设备 下载链接 https://download.csdn.net/download/zmlovelx/88382784 或网络搜索。 使用 opensuse可直接解压后使…...

Visio如何对文本打下标、上标,以及插入公式编辑器等问题(已解决)
解决这个问题的本质问题,就是在Visio中插入公式编辑器(这不是visio的常用命令,需要添加)。 打开Visio--》文件--选项 点击选项,弹出对话框。在自定义功能区中,点击 常用命令,在下拉选项中&#…...

快速将iPhone大量照片快速传输到电脑的办法!
很多使用iPhone 的朋友要将照片传到电脑时,第一时间都只想到用iTunes 或iCloud,但这2个工具真的都非常难用,今天小编分享牛学长苹果数据管理工具的照片传输功能,他可以快速的将iPhone照片传输到电脑上,并且支持最新的i…...
TCP/IP协议簇包含的协议
应用层(Application Layer): HTTP(Hypertext Transfer Protocol):用于Web浏览器和Web服务器之间的通信。HTTPS(Hypertext Transfer Protocol Secure):安全的HTTP版本&…...

天地图绘制区域图层
背景: 业务方要求将 原效果图 参考效果图 最终实现效果 变更点: 1.将原有的高德地图改为天地图 2.呈现形式修改:加两层遮罩:半透明遮罩层mask区域覆盖物mask 实现过程: 1.更换地图引入源 <link rel"style…...
git权限不够:Ask a project Owner or Maintainer to create a default branch
新仓库还未创建任何分支时,Developer角色时首次提交代码,抛如下异常 remote: GitLab: remote: A default branch (e.g. master) does not yet exist for galaxy/apache-jspf-project remote: Ask a project Owner or Maintainer to cre…...

AI在材料科学中的应用
7 AI在材料科学中的应用 在这一部分,我们将讨论AI技术在材料科学中的应用。首先,我们将介绍晶体材料的概述,并详细定义晶体材料的物理对称性,具体在第7.1节中讨论。接下来,我们将在第7.2节和第7.3节中讨论两个常见且基…...

VSCode快速设置heder和main函数
快速设置header: 点击左侧的齿轮,选择User Snippets: 在出现的选择框中输入python,选择python.json 在最外层的{ }内部添加以下内容 "HEADER": {"prefix": "header","body": ["# -*- encoding:…...

JimuReport积木报表 v1.6.2 版本正式发布—开源免费的低代码报表
项目介绍 一款免费的数据可视化报表,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等! Web 版报表设计器,类似于excel操作风格,通过拖拽完成报…...
sqlsession对象为什么不能被共享?
因为它是一个非线程安全的对象。每个SQLSession对象都维护了一个独立的数据库连接,以及与该连接相关的事务和缓存。如果多个线程共享同一个SQLSession对象,可能会导致数据混乱、事务冲突等问题。另外,SQLSession对象还包含了一级缓存…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...