首页 > 编程语言 >2024-02-23-物联网系统编程(4-信号)

2024-02-23-物联网系统编程(4-信号)

时间:2024-02-25 17:11:37浏览次数:23  
标签:02 set 23 int signal 2024 信号 进程 include

4. 信号

4.1 进程间通信概述

进程间通信
进程是一个独立的资源分配单元,不同进程(这里所说的进程通常指的是用户进程)之间的资源是独立的,没有关联,不能在一个进程中直接访问另一个进程的资源(例如打开的文件描述符)。
进程不是孤立的,不同的进程需要进行信息的交互和状态的传递等,因此需要进程间通信 (IPC,Inter Processes Communication)。

进程间通信功能:

  1. 数据传输:一个进程需要将它的数据发送给另一个进程
  2. 资源共享:多个进程之间共享同样的资源
  3. 通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件
  4. 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变

linux进程间通信(IPC)由以下几个部分:

  1. UNIX 进程间通信
  2. SYSTEM V进程间通信
  3. POSIX 进程间通信(POSIX:Portable Operating System interface 可移植操作系统接口)
  4. Socket 进程间通信

89817301-953c-42a9-98d5-582b235e29f3

进程间通信的实质

​ 系统只要创建一个进程,就会给当前进程分配4G的虚拟内存(32位操作系统),虚拟内存不是常说的内存条的空间,内存条的空间称之为物理内存,虚拟内存和物理内存之间存在映射关系,4G的虚拟内存分为3G的用户空间(0-3G)和1G(3-4G)的内核空间
​ 用户空间是进程所私有的,每一个进程的用户空间只能自己访问和使用,我们之前说的栈区、堆区数据区、代码区等都是用户空间的区域
​ 内核空间是所有进程所公有的,也就意味着绝大多数进程间通信方式,本质就是对内核空间的操作

特殊的进程间通信方式
socket通信可以实现不同主机的进程间通信,其他六个只能在一台主机的多个进程间通信信号通信是唯一的一种异步通信机制

​ 共享内存是所有进程间通信方式中效率最高的,他是直接对物理内存进行操作

4.2 信号的概述

4.2.1概述

信号是软件中断,它是在软件层次上对中断机制的一种模拟
信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突发事件。
信号是一种异步通信方式
进程不必等待信号的到达,进程也不知道信号什么时候到达。信号可以直接进行用户空间进程和内核空间进程的交互,内核进程可以利用它来通知用户空间进程发生了哪些系统事件。

每个信号的名字都以字符 SIG 开头。
每个信号和一个数字编码相对应,在头文件 signumh中,这些信号都被定义为正整数。
信号名定义路径(ubuntu 20.04 LTS):

usr/include/x86_64-linux-gnu/bits/signum.h

在Linux下,要想查看这些信号和编码的对应关系,可使用命令:kill-l

$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

信号是由当前系统已经定义好的一些标识,每一个标识都会在特定的场合使用并且都会对进程有一定的影响;

当信号产生时,会让当前信号做出相应的操作;

这些信号都是已经定义好的,我们不能自己再去创造,直接使用这些就可以;

4.2.2 产生信号的方式

  1. 当用户按某些终端键时,将产生信号。例如:

    1. 终端上按 Ctl+C 组合键通常产生中断信号 SIGINT
    2. 终端上按 Ctr+\ 键通常产生中断信号 SIGQUIT
    3. 终端上按 Ctr1+Z 键通常产生中断信号 SIGSTOP
    
  2. 硬件异常将产生信号

     除数为 0,无效的内存访问等, 这些情况通常由硬件检测到,并通知内核,然后内核产生适当的信号发送给相应的进程
    
  3. 软件异常将产生信号

    当检测到某种软件条件已经发生,并将其通知有关进程时,产生信号
    
  4. 调用 kill 函数将发送信号

    注意:接收信号进程和发送信号进程的所有者必须相同,或发送信号进程的所有者必须是超级用户
    
  5. 运行 kill命令将发送信号

    此程序实际上是使用 kill 函数来发送信号,也常用此命令终止一个失控的后台进程 
    

4.2.3 信号的默认(缺省)处理方式

当进程中产生了一个信号,就会让当前进程做出一定的反应默认处理进程的方式如下
1、终止进程:当信号产生后,当前进程就会立即结束
2、缺省处理:当信号产生后,当前进程不做任何处理
3、停止进程:当信号产生后,使得当前进程停止
4、让停止的进程回复运行:当信号产生后,停止的进程会回复执行(后台进程)

注意:每一个信号只有一个默认的处理方式

4.2.4 进程接收到信号后的处理方式

1、执行系统默认动作
	对大多数信号来说,系统默认动作是用来终止该进程
2、忽略此信号
	接收到此信号后没有任何动作
3、执行自定义信号处理函数
	用用户定义的信号处理函数处理该信号

注意: SIGKILLSIGSTOP这两个信号只能以默认的处理方式执行

4.2.5 常见的信号

信号 性质 默认处理方式
SIGKILL 9 产生这个信号,当前进程会退出,不能被缺省和捕捉 退出进程
SIGSTOP 19 产生这个信号,当前进程会停止,不能被缺省和捕捉 停止进程
SIGINT 2 键盘CTRL + C 退出进程
SIGQUIT 3 键盘CTRL + \ 退出进程
SIGTSTP 20 键盘CTRL + Z 退出进程
SIGCONT 18 当产生该信号后,当前停止的进程会恢复 停止进程恢复运行
SIGALRM 14 当调用alarm函数设置的时间到达后产生该信号 退出进程
SIGPIPE 13 当管道破裂时,会产生当前信号 退出进程
SIGABRT 6 调用abort函数时,产生当前信号 退出进程
SIGCHLD 17 当使用fork创建子进程时,如果子进程状态改变,会产生该信号 缺省
SIGUSR1 10 用户自定义信号,不会自动产生,只能用kill函数或者命令指定进程发送该信号 缺省
SIGUSR2 12 用户自定义信号,不会自动产生,只能用kill函数或者命令指定进程发送该信号 缺省

4.3 kill函数

kill 向一个进程发送信号

#include <sys/types.h>
#include <signal.h>

int kill(pid t pid, int signum);
功能:
	给指定进程发送信号参数;
pid: 详见下页
signum: 信号的编号;
返回值:
	成功返回 0,失败返回 -1。
pid的取值有 4种情况:
    pid>0: 将信号传送给进程 ID 为 pid 的进程。
    pid=0: 将信号传送给当前进程所在进程组中的所有进程
    pid=-1: 将信号传送给系统内所有的进程
    pid<-1: 将信号传给指定进程组的所有进程。这个进程组号等于 pid的绝对值
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    { // 父进程
        while (1)
        {
            printf("this is a parent process\n");
            sleep(1);
        }
    }
    else
    { // 子进程代码区
        printf("this is a son process\n");
        // 子进程在3秒以后,让父进程退出
        sleep(3);
        // 使用kill给父进程发送信号,父进程接收到信号后直接退出就可以了
        kill(getppid(), SIGKILL);
    }
    return 0;
}

输出结果

this is a son process
this is a parent process
this is a parent process
this is a parent process
已杀死

4.4 alarm函数

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:
	在 seconds 秒后,向调用进程发送一个 SIGALRM 信号,SIGALRM 信号的默认动作是终止调用 alarm 函数的进程;
返回值:
	若以前没有设置过定时器,或设置的定时器己超时返回 0;
	否则返回定时器剩余的秒数,并重新设定定时器。
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    unsigned int sec;
    // 当执行到alarm之后,代码会接着往下执行,当设定的时间到后,会产生SIGALRM信号
    //如果alarm之前没有设置其他闹钟,则返回8,如果之前设置了,则返回之前剩余的秒数
    //如果一个程序中出现多个alarm闹钟,第一个如果没有到达指定的时间就遇到第二个
    //则第一个的闹钟时间清除,按照第二个alarm闹钟的时间继续向下运行
    sec = alarm(5);
    printf("sec = %d\n", sec);
    sleep(3);
    sec = alarm(6);
    printf("sec = %d\n", sec);
    while (1)
    {
        printf("hello world\n");
        sleep(1);
    }

    return 0;
}

输出结果

sec = 0
sec = 2
hello world
hello world
hello world
hello world
hello world
hello world
闹钟

4.5 raise函数

#include<signal.h>
int raise(int sig);
功能:给调用进程本身发送信号;
参数:
	sig:指定的信号;
返回值:
	成功: 0
	失败: 非0
raise(sig) <==> kill(getpid(),sig)
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int num = 0;
    while (1)
    {
        printf("hello world\n");
        sleep(1);
        num++;
        if (num == 5)
        {
            // 当循环执行5秒后,进程退出
            // 使用raise给当前进程本身发送信号
            // 此处亦可使用
            // kill(getpid(),SIGALRM);
            raise(SIGALRM);
        }
    }

    return 0;
}
hello world
hello world
hello world
hello world
hello world
闹钟

4.6 abort 函数

#include <stdlib.h>
void abort(void);
功能:
	向进程发送一个 SIGABRT 信号,默认情况下进程会退出。
注意:
	即使 SIGABRT 信号被加入阻塞集,一旦进程调用了 abort 函数,进程也还是会被终止,且在终止前会刷新缓冲区,关闭文件描述符。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int num = 0;
    while (1)
    {
        printf("hello world\n");
        sleep(1);
        num++;
        if (num == 5)
        {
            // 当循环执行5秒后,进程退出
            // 使用 abort 终止进程

            abort();
        }
    }

    return 0;
}

输出结果

hello world
hello world
hello world
hello world
hello world
已放弃 (核心已转储)

4.7 pause函数

#include <unistd.h>
int pause(void);
功能:
	将调用进程挂起直至捕捉到信号为止, 这个函数通常用于判断信号是否已到;
参数: 无
返回值:
	直到捕获到信号,pause 函数才返回-1,且errno被设置成 EINTR
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    { // 父进程

        printf("this is a parent process\n");
        // 使用pause函数阻塞,等待信号
        pause();
    }

    else
    { // 子进程代码区
        printf("this is a son process\n");
        // 子进程在3秒以后,让父进程退出
        sleep(3);
        // 使用kill给父进程发送信号,父进程接收到信号后直接退出就可以了
        kill(getppid(), SIGKILL);
    }
}

输出结果

this is a parent process
this is a son process
已杀死

4.8 signal函数

进程接收到信号后的处理方式

  1. 执行系统默认动作

  2. 忽略此信号

  3. 执行自定义信号处理函数

程序中可用函数 signal()改变信号的处理方式

#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
	typedef void (*sighander_t)(int);
	sighandler_t signal(int signum, sighandler_t handler);
功能:
	注册信号处理函数(不可用于 SIGKILL、SIGSTOP 信号),即确定收到信号后处理函数的入口地址;
参数:
	signum: 信号编号
handler 的取值:
    忽略该信号:SIG_IGN
    执行系统默认动作:SIG_DFL
    自定义信号处理函数:信号处理函数名
返回值:
	成功:返回函数地址,该地址为此信号上一次注册的信号处理函数的地址;
	失败:返回 SIG_ERR

4.8.1 signal函数的使用

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
void handler(int sig);

int main(int argc, char const *argv[])
{
// 1. 以默认的方式处理信号
#if 0
    if (signal(SIGINT, SIG_DFL) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }
    if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }
    if (signal(SIGTSTP, SIG_DFL) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }

#endif

// 2. 以忽略的方式处理信号 SIG_IGN
#if 0
    if (signal(SIGINT, SIG_IGN) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }
    if (signal(SIGQUIT, SIG_IGN) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }
    if (signal(SIGTSTP, SIG_IGN) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }

#endif


// 3. 以用户自定义方式处理信号 handler
#if 1
    if (signal(SIGINT, handler) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }
    if (signal(SIGQUIT, handler) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }
    if (signal(SIGTSTP, handler) == SIG_ERR)
    {
        perror("fail to signal");
        exit(1);
    }

#endif

    while (1)
    {
        printf("hello world\n");
        sleep(1);
    }

    return 0;
}

void handler(int sig)
{
    if (sig == SIGINT)
    {
        printf("SIGINT正在处理\n");
    }
    if (sig == SIGQUIT)
    {
        printf("SIGQUIT正在处理\n");
    }
    if (sig == SIGSTOP)
    {
        printf("SIGSTOP正在处理\n");
    }
}

4.8.2 signal函数的返回值

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

void *ret_handler;

void handler(int sig)
{
    printf("**************************\n");
    printf("hello world\n");
    printf("welcome to beijing\n");
    printf("**************************\n");
    if (signal(SIGINT, ret_handler) == SIG_ERR)
    {
        perror("fail to signal\n");
        exit(1);
    }
}

int main(int argc, char const *argv[])
{
    if ((ret_handler = signal(SIGINT, handler)) == SIG_ERR)
    {
        perror("fail to signal\n");
        exit(1);
    }

    while (1)
    {

        printf(" I love C\n");
        sleep(1);
    }
    return 0;
}

输出结果

I love C
 I love C
 I love C
^C**************************
hello world
welcome to beijing
**************************
 I love C
 I love C
^C

第一次按ctrl + c,触发信号中断函数,此次以自定义的方式处理,执行handler函数,返回值为ret_handler。 返回值是当前信号上一次的处理方式,此时的ret_handlerSIGINT的默认方式

再次按ctrl + c,就会使用默认的方式,中断进程并退出。

4.8.3 可重入函数

​ 可重入函数是指函数可以由多个任务并发使用,而不必担心数据错误;
​ 可重入函数就是可以被中断的函数,当前函数可以在任何时刻中断它,并执行另一块代码当执行完毕后,回到原本的代码还可以正常继续运行。

编写可重入函数:

  1. 不使用(返回)静态的数据、全局变量(除非用信号量互斥)
  2. 不调用动态内存分配、释放的函数
  3. 不调用任何不可重入的函数(如标准I/0函数)1f37d0ba-49b6-4ecb-9a3c-a0329f6b874b
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

void handler(int sig)
{
    printf("SIGINT\n");
}

int main(int argc, char const *argv[])
{
    signal(SIGINT, handler);
#if 1
    // sleep(5); // 按下ctrl+c 会中断函数,其是可重入函数,但是由于其本身性质,就会中断;
    alarm(5); // alarm是可重入函数,当它执行的时候,如果有其他信号传入并执行处理函数,执行完毕后,会继续回到alarm函数
    while (1)
    {
        printf("hello world\n");
        sleep(1);
    }

#endif
    return 0;
}

输出结果

hello world
hello world
^CSIGINT
hello world
hello world
hello world
hello world
闹钟
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

void handler(int sig)
{
    printf("SIGINT\n");
}

int main(int argc, char const *argv[])
{
    signal(SIGINT, handler);
#if 0
    // sleep(5); // 按下ctrl+c 会中断函数,其是可重入函数,但是由于其本身性质,就会中断;
    alarm(5); // alarm是可重入函数,当它执行的时候,如果有其他信号传入并执行处理函数,执行完毕后,会继续回到alarm函数
    while (1)
    {
        printf("hello world\n");
        sleep(1);
    }

#endif

#if 1
    char buf[32] = "";
    if (read(0, buf, 20) == -1) 
    // read也是可重入函数,在等待终端输入时,如果产生信号并执行信号处理函数,
    // 信号处理函数执行完毕后,可继续输入数据,read读取信号处理函数之后的数据
    {
        perror("fail to read\n");
        exit(1);
    }
    printf("buf = [%s]\n", buf);
#endif
    return 0;
}

输出结果

123^CSIGINT
asd^CSIGINT
fgh
buf = [fgh
]

4.9 信号集

4.9.1 信号集概述

​ 一个用户进程常常需要对多个信号做出处理。为了方便对多个信号进行处理,在 Linux 系统中引入了信号集。信号是用来表示多个信号的数据类型

4.9.2 信号集数据类型

sigset_t

4.9.3 信号集相关操作

sigemptyset; // 初始化空的信号集
sigfillset; // 初始化满的信号集
sigismember; // 判断信号是否为信号集成员
sigaddset; // 添加一个信号到信号集
sigdelset; // 删除信号集的一个信号
sigemptyset()
#include<signal.h>
int sigemptyset(sigset t*set);
功能:
	初始化由set指向的信号集,清除其中所有的信号即初始化一个空信号集;
参数:
	set:信号集标识的地址,以后操作此信号集,对set进行操作就可以了;
返回值:
    成功返回 0
    失败返回 -1
// --------------------------------------------------------------------        
sigfillset()
#include <signal.h>
int sigfillset(sigset t *set);
功能:
	初始化信号集合set,将信号集合设置为所有信号的集合;
参数:
	信号集标识的地址,以后操作此信号集,对set进行操作就可以了;
返回值:
	成功返回 0
	失败返回 -1
// --------------------------------------------------------------------    
sigismember()
#include <signal.h>
int sigismember(const sigset t*set,int signum);
功能:
	查询signum标识的信号是否在信号集合set之中;
参数:
	set:信号集标识符号的地址。
	signum:信号的编号。
返回值:
	成功:在信号集中返回1,不在信号集中返回0;
	错误,返回-1
// --------------------------------------------------------------------    
sigaddset()
#include<signal.h>
int sigaddset(sigset t*set, int signum);
功能:
	将信号signum加入到信号集合set之中。
参数:
	set:信号集标识的地址。
	signum:信号的编号;
返回值:
    成功返回 0
    失败返回 -1
// --------------------------------------------------------------------    
sigdelset()
#include<signal.h>
int sigdelset(sigset t*set,int signum);
功能:
	将signum所标识的信号从信号集合set中删除;
参数:
    set:信号集标识的地址。
    signum:信号的编号;
返回值:
	成功:返回 0
	失败:返回 -1
#include <signal.h>
#include <stdio.h>
#include <bits/types/sigset_t.h>

int main(int argc, char const *argv[])
{
    sigset_t set;
    int ret = 0;
    // 初始化空的信号集
    sigemptyset(&set);
    // 判断SIGIN信号是否在信号集中
    ret = sigismember(&set, SIGINT);
    if (ret == 0)
    {
        printf("SIGINT is not a number of sigprocmask \nret = %d\n", ret);
    }
    // 将指定的信号添加到集合中
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGQUIT);

    // 再次判断SIGIN信号是否在信号集中
    ret = sigismember(&set, SIGINT);
    if (ret == 0)
    {
        printf("SIGINT is not a number of sigprocmask \nret = %d\n", ret);
    }
    else
    {
        printf("SIGINT is  a number of sigprocmask \nret = %d\n", ret);
    }

    return 0;
}

输出结果

SIGINT is not a number of sigprocmask 
ret = 0
SIGINT is  a number of sigprocmask 
ret = 1

4.9.4 信号阻塞集(屏蔽集、掩码)

​ 每个进程都有一个阻塞集,它用来描述哪些信号递送到该进程的时候被阻塞(在信号发生时记住直到进程准备好时再将信号通知进程)。
​ 所谓阻塞并不是禁止传送信号,而是暂缓信号的传送。若将被阻塞的信号从信号阻塞集中删除,且对应的信号在被阻塞时发生了,进程将会收到相应的信号。

#include<signal.h>
int sigprocmask(int how,const sigset t *set, sigset t *oldset);
功能:检查或修改信号阻塞集,根据how指定的方法对进程的阻塞集合进行修改,新的信号阻塞由set指定,而原先的信号阻塞集合由oldset保存;
参数:
	how:信号阻塞集合的修改方法:
		SIG_BLOCK:向信号阻塞集合中添加set信号集;
		SIG_UNBLOCK:从信号阻塞集合中删除set信号集;
         SIG_SETMASK:将信号阻塞集合设为set集合
           
	set:要操作的信号集地址。
	oldset:保存原先信号集地址。
注:若set为NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到oldset中;
返回值:
	成功:返回0
	失败:返回 -1
#include <signal.h>
#include <stdio.h>
#include <bits/types/sigset_t.h>
#include <unistd.h>
#include <stdlib.h>
#include <bits/sigaction.h>

int main(int argc, char const *argv[])
{

    int i = 0;
    // 创建信号集
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    while (1)
    {
        // 将set信号集添加到信号阻塞集中
        sigprocmask(SIG_BLOCK, &set, NULL);
        for (i = 0; i < 5; i++)
        {
            printf("SIGINT signal is blocked\n");
            sleep(1);
        }
        // 将set信号集从信号阻塞集中删除
        sigprocmask(SIG_UNBLOCK, &set, NULL);
        for (i = 0; i < 5; i++)
        {
            printf("SIGINT signal is unblocked\n");
            sleep(1);
        }
    }

    return 0;
}

输出结果

SIGINT signal is blocked
SIGINT signal is blocked
^CSIGINT signal is blocked
SIGINT signal is blocked
SIGINT signal is blocked

在被阻塞的时候,ctrl+c不好使,等解除阻塞,会执行ctrl+c,中断程序。

标签:02,set,23,int,signal,2024,信号,进程,include
From: https://www.cnblogs.com/hasaki-yasuo/p/18032617

相关文章

  • 2024牛客寒假算法基础集训营6
    A.欧拉筛处理出素数直接3重暴力循环找#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;#defineinf0x3f3f3f3fboolis_prime[N];//是否是质数,0为是,1为不是intprime[N];//质数数组inttop=1;//质数的下标intmin_p[N];//最小......
  • 2023蓝桥杯省赛B组真题及解析
    2023蓝桥杯省赛B组真题及解析7.子串简写算法:前缀和https://www.lanqiao.cn/problems/3514/learning/?subject_code=1&group_code=4&match_num=14&match_flow=1&origin=cup#include<bits/stdc++.h>using namespace std;int main(){    int K;    cin>>K; ......
  • 2024牛客寒假算法基础集训营6 H 纷乱的红线 题解
    Question2024牛客寒假算法基础集训营6H纷乱的红线小红拿到了一个圆,以及平面上有\(n\)个点(保证没有三点共线)。现在小红将随机取\(3\)个点画一个三角形,她想知道这个三角形和圆的交点数量的期望是多少?Solution考虑到\(n\le1000\)可以枚举每一条线,计算这一条线和圆的交......
  • 1.23
    SpringBoot是伴随着Spring4.0诞生的,从字面理解,Boot是引导的意思,因此SpringBoot旨在帮助开发者快速搭建Spring 框架。SpringBoot继承了原有Spring框架的优秀基因,使Spring在使用中更加方便快捷。......
  • 2024牛客寒假算法基础集训营6 G 人生的起落 题解
    Question2024牛客寒假算法基础集训营6G人生的起落定义一个三元组\((x,y,z)\)是“v-三元组”当且仅当该三元组满足以下条件:\(x=z\)\(x>y\)现在需要你构造一个\(n\)个正整数组成的数组,所有元素之和恰好等于\(S\),且恰好有\(k\)个长度威\(3\)的连续子数组......
  • HGAME 2024 WEEK3 crypto
    CRYPTOexRSA题目描述:RRRSAfromCrypto.Util.numberimport*fromsecretimportflagm=bytes_to_long(flag)p=getStrongPrime(1024)q=getStrongPrime(1024)phi=(p-1)*(q-1)e1=inverse(getPrime(768),phi)e2=inverse(getPrime(768),phi)e3=inverse(getPrime(768),phi)......
  • CF1923 VP 记录
    CF1923VP记录AB跳了。C.FindB赛时切了。题意如果存在一个整数数组\(b\)满足以下条件,则认为一个整数数组\(a\)是好的:\(|b|=|a|\)。\(a_i\neqb_i\)。\(\sumb=\suma\)。\(b_i>0\)。给定一个数组\(c\),\(q\)次询问,要求判断\(c[l,r]\)是不是好的数组。可以......
  • 最佳软件架构书籍终极清单 (2024)
          软件架构是成功开发软件产品的基础。精心设计的软件架构可以大大提高系统的质量。它还有助于降低出错风险,并使将来添加新特性和功能变得更加容易。在这篇博文中,我将为您列出2024年最值得一读的软件架构书籍,以及2024年将出版哪些有趣的软件架构书籍。当然,这些书籍......
  • 2024-02-25 闲话
    昨天晚上ABC有prize,然后我和车昱辉本来说问郭军凯要不要acm。后来想了想还是自己玩了玩。现在发现这个决策实在是太明智了,因为:车昱辉:上半学期感觉他一点动静都还没有呢?yspm:这把属于是闷声发大财。车昱辉还有一条锐评,但是实在是太锐了,我强烈怀疑他的大脑里内置了patternr......
  • 读人工不智能:计算机如何误解世界笔记02_Hello,world
    1. Hello,world1.1. “Hello,world”是布赖恩·克尼汉和丹尼斯·里奇于1978年出版的经典著作《C程序设计语言》中的第一个编程项目1.2. 贝尔实验室可以说是现代计算机科学界中的智库,地位好比巧克力界的好时巧克力1.3. 计算机科学界的大量创新都起源于贝尔实验室1.3.1. 激......