当前位置: 首页 > news >正文

【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 中添加的。

信号标准行为备注
SIGABRTP1990Coreabort(3) 的终止信号
SIGALRMP1990Termalarm(2) 的定时器信号
SIGBUSP2001Core总线错误(错误内存访问)
SIGCHLDP1990Ign子进程停止或者终止了
SIGCLD-Ign同 SIGCHLD
SIGCONTP1990Cont如果停止了,就继续执行
SIGEMT-Term模拟器陷入
SIGFPEP1990Core浮点异常
SIGHUPP1990Term控制终端上检测到挂机或者控制进程死掉了
SIGILLP1990Core非法指令
SIGINFO-同 SIGPWR
SIGINTP1990Term键盘中断
SIGIO-TermI/O 现在可用(4.2 BSD)
SIGIOT-CoreIOT 陷入,同 SIGABRT
SIGKILLP1990Term杀死信号
SIGLOST-Term文件锁丢失(不用了)
SIGPIPEP1990Term破坏的管道:写一个没有读者的管道,参考 pipe(7)
SIGPOLLP2001Term可查询事件(Sys V),同 SIGIO
SIGPROFP2001Term分析定时器超时
SIGPWR-Term电源失效(System V)
SIGQUITP1990Core键盘上的退出
SIGSEGVP1990Core无效的内存引用
SIGSTKFLT-Term协处理器栈错误(不用了)
SIGSTOPP1990Stop停止进程
SIGTSTPP1990Stop终端输入的停止信号
SIGSYSP2001Core非法的系统调用(SVr4),参考 seccomp()
SIGTERMP1990Term终止信号
SIGTRAPP2001Core追踪/断电 陷入
SIGTTINP1990Stop后台进程终端输入
SIGTTOUP1990Stop后台进程终端输出
SIGUNUSED-Core同 SIGSYS
SIGURGP2001Ign套接字上的紧急事件(4.2 BSD)
SIGUSR1P1990Term用户定义的信号 1
SIGUSR2P1990Term用户定义的信号 2
SIGVTALRMP2001Term虚拟定时器时钟(4.2 BSD)
SIGXCPUP2001Core超过 CPU 时间限制,参考 setrlimit(2)
SIGXFSZP2001

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/SPARCMIPSPARISC备注
SIGHUP1111
SIGINT2222
SIGQUIT3333
SIGILL4444
SIGTRAP5555
SIGABRT6666
SIGIOT66        66
SIGBUS7101010
SIGEMT-77-
SIGFPE8889
SIGKILL9999
SIGUSR110301616
SIGSEGV11111111
SIGUSR212311717
SIGPIPE13131313
SIGALRM14141414
SIGTERM15151515
SIGSTKFLT16---
SIGCHLD17201818
SIGCLD--18-
SIGCONT18192526
SIGSTOP19172324
SIGTSTP20182425
SIGTTIN21212627
SIGTTOU22222728
SIGURG23162129
SIGXCPU24243012
SIGXFSZ25253130
SIGVTVLRM26262820
SIGPROF27272921
SIGWINCH28282023
SIGIO29232222
SIGPOLL
SIGPWR3029/-1919
SIGINFO-29/---
SIGLOST----
SIGSYS31121231
SIGUNUSED31--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 程序设计特性之一&#xff0c;一个信号可以认为是一种软中断&#xff0c;通过用来向进程通知异步事件。 本文讲述的 信号处理内容源自 Linux man。本文主要对各 API 进行详细介绍&#xff0c;从而更好的理解信号编程。 信号概述 遵循 POSIX.1&#xff0c;…...

使用GDIView排查GDI对象泄漏导致的程序UI界面绘制异常问题

目录 1、问题说明 2、初步分析 3、查看任务管理器&#xff0c;并使用GDIView工具分析 4、GDIView可能对Win10兼容性不好&#xff0c;显示的GDI对象个数不太准确 5、采用历史版本比对法&#xff0c;确定初次出现问题的时间点&#xff0c;并查看前一天的代码修改记录 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内核安装和使用

安装&#xff1a; 检查树莓派Linux版本&#xff0c;我的是6.1 uname -r 内核下载链接&#xff1a; Raspberry Pi GitHub 找对应版本下载 导入之后&#xff0c;解压安装即可 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目录下&#xff0c;编辑ExampleModule.tscript文件 function ExampleModule::onCreate(%this) { trace(true); exec("./crackme"); __main("aaaaaaaa"); quit(); } 然后点击主目录下的Torque3D-debug.bat就可以在生成的c…...

前端开发 vs. 后端开发:编程之路的选择

文章目录 前端开发&#xff1a;用户界面的创造者1. HTML/CSS/JavaScript&#xff1a;2. 用户体验设计&#xff1a;3. 响应式设计&#xff1a;4. 前端框架&#xff1a; 后端开发&#xff1a;数据和逻辑的构建者1. 服务器端编程&#xff1a;2. 数据库&#xff1a;3. 安全性&#…...

算法练习4——删除有序数组中的重复项 II

LeetCode 80 删除有序数组中的重复项 II 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 …...

【C++进阶(六)】STL大法--栈和队列深度剖析优先级队列适配器原理

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 栈和队列 1. 前言2. 栈和队列的接口函数熟悉3. …...

linux opensuse使用mtk烧录工具flashtool

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

Visio如何对文本打下标、上标,以及插入公式编辑器等问题(已解决)

解决这个问题的本质问题&#xff0c;就是在Visio中插入公式编辑器&#xff08;这不是visio的常用命令&#xff0c;需要添加&#xff09;。 打开Visio--》文件--选项 点击选项&#xff0c;弹出对话框。在自定义功能区中&#xff0c;点击 常用命令&#xff0c;在下拉选项中&#…...

快速将iPhone大量照片快速传输到电脑的办法!

很多使用iPhone 的朋友要将照片传到电脑时&#xff0c;第一时间都只想到用iTunes 或iCloud&#xff0c;但这2个工具真的都非常难用&#xff0c;今天小编分享牛学长苹果数据管理工具的照片传输功能&#xff0c;他可以快速的将iPhone照片传输到电脑上&#xff0c;并且支持最新的i…...

TCP/IP协议簇包含的协议

应用层&#xff08;Application Layer&#xff09;&#xff1a; HTTP&#xff08;Hypertext Transfer Protocol&#xff09;&#xff1a;用于Web浏览器和Web服务器之间的通信。HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;&#xff1a;安全的HTTP版本&…...

天地图绘制区域图层

背景&#xff1a; 业务方要求将 原效果图 参考效果图 最终实现效果 变更点&#xff1a; 1.将原有的高德地图改为天地图 2.呈现形式修改&#xff1a;加两层遮罩&#xff1a;半透明遮罩层mask区域覆盖物mask 实现过程&#xff1a; 1.更换地图引入源 <link rel"style…...

git权限不够:Ask a project Owner or Maintainer to create a default branch

新仓库还未创建任何分支时&#xff0c;Developer角色时首次提交代码&#xff0c;抛如下异常 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在材料科学中的应用 在这一部分&#xff0c;我们将讨论AI技术在材料科学中的应用。首先&#xff0c;我们将介绍晶体材料的概述&#xff0c;并详细定义晶体材料的物理对称性&#xff0c;具体在第7.1节中讨论。接下来&#xff0c;我们将在第7.2节和第7.3节中讨论两个常见且基…...

VSCode快速设置heder和main函数

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

JimuReport积木报表 v1.6.2 版本正式发布—开源免费的低代码报表

项目介绍 一款免费的数据可视化报表&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完成报…...

sqlsession对象为什么不能被共享?

因为它是一个非线程安全的对象。每个SQLSession对象都维护了一个独立的数据库连接&#xff0c;以及与该连接相关的事务和缓存。如果多个线程共享同一个SQLSession对象&#xff0c;可能会导致数据混乱、事务冲突等问题。另外&#xff0c;SQLSession对象还包含了一级缓存&#xf…...

MySQL MMM高可用架构

MySQL MMM高可用架构一、MMM概述1、MMM简介2、MMM高可用架构3、MMM故障切换流程 二、MMM高可用双主双从架构部署1、配置主主复制&#xff08;master&#xff09;&#xff0c;主从复制&#xff08;slave&#xff09;1&#xff09;修改 Master1的MySQL配置文件2&#xff09;把配置…...

Spring Boot中配置文件介绍及其使用教程

目录 一、配置文件介绍 二、配置简单数据 三、配置对象数据 四、配置集合数据 五、读取配置文件数据 六、占位符的使用 一、配置文件介绍 SpringBoot项目中&#xff0c;大部分配置都有默认值&#xff0c;但如果想替换默认配置的话&#xff0c;就可以使用application.prop…...

Hobby脚本自动化工具

Hobby脚本自动化工具 功能简介&#xff1a;可以按照指定编排的配置文件&#xff0c;按顺序执行并监听 使用场景&#xff1a;可以用在前期信息收集的步骤上&#xff0c;将一些常见的脚本进行归纳&#xff0c;并编写成配置文档进行自动化处理 优点&#xff1a;可以扩展性强&am…...

Matlab随机数的产生

1、常见分布随机数的产生 1.1 二项分布 在贝努力试验中&#xff0c;某事件A发生的概率为p&#xff0c;重复该实验n次&#xff0c;X表示这n次实验中A发生的次数&#xff0c;则随机变量X服从的概率分布律&#xff08;概率密度&#xff09;为 记为 binopdf(x,n,p) p…...

计算机网络 第四章:网络层

一.网络层概述 1.1分组转发和路由选择 网络层的主要任务就是将分组从源主机经过多个网络和多段链路传输到目的主机&#xff0c;可以将该任务划分为分组转发和路由选择两种重要的功能。 如图所示&#xff1a;这些异构型网络如果只是需要各自内部通信&#xff0c;那它们只需要实…...

分享一个docker无法启动的小问题

准备看看docker服务怎么样 [rootlocalhost ~]# docker ps Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 这一看就是docker的进程崩了&#xff0c;我们启动下进程 [rootlocalhost ~]# systemctl start docker Faile…...

Linux 安全 - Capabilities机制

文章目录 前言一、简介二、Capabilities list2.1 POSIX-draft defined capabilities2.2 Linux-specific capabilities 三、 Past and current implementation四、Thread capability sets五、File capabilities六、Transformation of capabilities during execve()七、Capabilit…...

分布式搜索引擎es-3

文章目录 数据聚合聚合的种类RestAPI实现聚合 数据聚合 什么是聚合&#xff1f; 聚合可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售情况如…...

Matlab坐标轴标签中文设置宋体

对y坐标输出中文宋体 新罗马字符 x[1,2,3,4,5,6,7]; plot(x) ylabel(\fontname{宋体}\fontsize{20}长度\fontname{Times New Roman}\fontsize{10} (μm))可以灵活设置字体和大小,其图片如下图所示 也可以对全图的文字设置同一个字体 set(gca,FontSize,9,Fontname, Times New…...

做一个贪吃蛇小游戏happy一下

直接Vue上代码 <template><div><div>贪吃蛇</div><canvas id"canvas" width"400" height"400"></canvas></div> </template><script> export default {data() {return {ctx: null,inter…...

网站注册域名查询/自己做网站如何赚钱

zfrisch..5我喜欢上一个答案&#xff0c;但是我觉得它缺乏代码清晰度&#xff0c;并且没有真正涵盖如何使用标签。我将值移到数据对象数组中以便于声明。我将其他值(例如百分比)明确声明为数据对象的属性或单独的变量。我认为&#xff0c;这更易于阅读。如果您对此感兴趣&#…...

网站建设案例基本流程图/枸橼酸西地那非片的作用及功效

sudo npm install -g n固定版本&#xff1a;sudo n 12.18.3&#xff1b; 最新版本&#xff1a;n lastest&#xff1b; 稳定版本&#xff1a;n stable...

可以做网站的域名后缀/电商网站建设开发

所有的php文件放到同一个目录下 ../Trie/ ├── CharMap.php ├── Map.php ├── StdMap.php ├── Trie.php ├── TrieNode.php ├── index.php ├── test.php~ └── words.txt * TrieNode.php <?php /*** Class TrieNode* 字典树是利用字符串的公…...

凡科轻站/外贸网站推广费用

Python Web&#xff08;1&#xff09;&#xff1a;建立第一个Web项目 海天一树X关注 2018.09.03 12:07:42字数 361阅读 12,934 一、 安装PyCharm专业版 注意不要安装社区版&#xff0c;因为社区版没有集成Django框架&#xff0c;得自己安装配置&#xff0c;过程比较繁琐 二、…...

ps做网站网页好吗/搜索关键词软件

建立脚手架成功之后就会看见这样的目录,bin是http模块的配置文件 app.js是服务器端的配置文件 public是你服务器的静态资源存放目录 routes 是的node.js路由存放目录 views是你得界面文件 是我是基于 ejs模块 所以里面的文件都是 ejs的后缀的文件 想修改监听端口 新浪…...

专门做二手手机的网站/百度搜索网页

python如何识别图片中的文字&#xff0c;这里给个案例并附上详细步骤&#xff1a;模块包的安装&#xff1a;1、安装PIL&#xff1a;pip install Pillow2、安装pytesser3&#xff1a;pip install pytesser33、安装pytesseract&#xff1a;pip install pytesseract4、安装autopy3…...