Linux进程信号

article/2025/6/10 17:46:04

目录

信号的认识

技术应用角度的信号

信号处理函数

信号概念

信号处理

忽略此信号

执行默认处理动作

产生信号

基本操作

调用系统命令向进程发送信号

闲聊

使用函数产生信号

raise函数

abort

由软件条件产生信号

puase函数

测试

如何理解软件条件

硬件异常产生信号

子进程退出core dump​编辑

Core Dump

 保存信号

信号其他相关常见概念

在内核中的表示

sigset_t

信号集操作函数

sigprocmask

sigpending

测试

捕捉信号

信号处理流程

流程

sigaction

sa_handler

sa_mask

硬件中断

时钟中断

软中断

缺页中断?内存碎片处理?除零野指针错误?

理解内核态与用户态

volatile

例子


信号的认识

举个例子,在生活中,信号可以理解为“通知”,你收到了某个“通知”,所以你要在合适的时候去做某件事

但是这个信号是什么时候到的你并不知道,因此信号异步

要怎么处理你也需要定好,处理信号也可以分为:默认、自定义、忽略 三种

技术应用角度的信号

#include <iostream>
#include <unistd.h>
int main()
{while(true){std::cout << "I am a process, I am waiting signal!" << std::endl;sleep(1);}
}

 上面这段代码,在程序上是每隔一秒钟在控制台打印消息

但是你也可以选择按下ctrl+c将进程关闭掉,实际上就是ctrl+c这个键盘输入产生一个硬件中断被操作系统获取,并被解释为信号,发送给目标前台进程

目标前台进程收到消息之后引起进程退出

信号处理函数

#include <signal.h>
//定义一个参数为int类型,返回值为空的函数指针类型为sighandler_t
typedef void (*sighandler_t)(int);//我们可以将写好的的信号处理函数交给对应的信号,当收到对应的信号时就执行对应的回调方法
sighandler_t signal(int signum, sighandler_t handler);//signum为对应的信号编号,handler为自定义的信号处理函数

同样以ctrl+c为例,ctrl+c实际上是向前台进程发送2号信号SIGINT,这里,我们可以做一个实验

#include<iostream>
#include<unistd.h>
#include<signal.h>
void handle(int signum)
{std::cout<<"我是进程:"<<getpid()<<",我收到了"<<signum<<"号信号,执行回调方法"<<std::endl;
}
int main()
{signal(SIGINT,handle);while(true){std::cout<<"我是进程:"<<getpid()<<",我在等待"<<std::endl;sleep(1);}return 0;
}

此时,我们就将2号信号SIGINT(即ctrl+c发送的信号)修改为了我们的自定义方法

此时我们发现进程关不掉了,我们可以通过

kill -9 进程pid

这个命令来直接杀死掉对应的进程即可

不过要注意下,我们写的回调方法只是定义了收到某个信号时对应的处理方法,也就是说,如果我们收不到对应信号,那么我们就永远也不会执行对应的回调方法

信号概念
 

信号是进程之间事件异步通知的⼀种方式,属于软中断。

我们可以通过 kill -l 命令查看信号

我们也可以直接去signal.h头文件中去查看信号的宏定义

因此我们可以发现SIGINT实际上就是2

信号处理
 

我们上面已经写过了信号处理函数,我们再来解释下其他的信号处理

忽略此信号
 

我们只要设置对应信号的处理函数为SIG_IGN那么我们就可以忽略掉对应的信号了 

即 signal ignore

#include<iostream>
#include<unistd.h>
#include<signal.h>
int main()
{signal(SIGINT,SIG_IGN);while(true){std::cout<<"我是进程:"<<getpid()<<",我在等待"<<std::endl;sleep(1);}return 0;
}

执行默认处理动作

 设置信号处理函数为SIG_DFL

即 signal default

#include<iostream>
#include<unistd.h>
#include<signal.h>
void handle(int signum)
{std::cout<<"我是进程:"<<getpid()<<",我收到了"<<signum<<"号信号,执行回调方法"<<std::endl;signal(SIGINT,SIG_DFL);std::cout<<"已经将回调方法设置为默认方法"<<std::endl;
}
int main()
{signal(SIGINT,handle);while(true){std::cout<<"我是进程:"<<getpid()<<",我在等待"<<std::endl;sleep(1);}return 0;
}

提供⼀个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为自
定义捕捉(Catch)⼀个信号。


我们从源码可以看到,SIG_DFL,SIG_IGN实际上就是将0,1强转为函数指针类型

产生信号
 

基本操作
 

Ctrl+\(SIGQUIT)可以发送终止信号并生成core dump文件(3号信号)

Ctrl+Z(SIGTSTP)可以发送停止信号,将当前前台进程挂起到后台等。(20号信号)
 

调用系统命令向进程发送信号

其实就是上文的kill命令

ctrl+c发送的是2号信号,所以我们可以输入

kill -2 进程pid

我们也可以写出

kill -SIGINT 进程pid(因为SIGINT本来就宏定义为2

所以信号可以使用数字,也可以使用宏

闲聊

然后我们在这里随便说一下为什么信号的指令是kill

其实很简单,kill一开始就是作为终止信号来结束进程而诞生的,但是后来发现单单的结束进程还不够,可能还需要暂停,恢复进程等其他功能,但是吧,到那会,kill命令已经使用很久了,也不可能一下子让所有用户都知道kill命令换了个名字用来代表发送信号吧,因此就继续使用kill命令来发送信号

使用函数产生信号

int kill(pid_t pid, int sig);
//On success (at least one signal was sent), zero is returned. On error,
//-1 is returned, and errno is set appropriately.

没错,kill命令的函数名也是kill,我们通过这个函数向指定进程发送指定信号

raise函数
 

让进程自己给自己发送信号

int raise(int sig);

#include<iostream>
#include<unistd.h>
#include<signal.h>
void handle(int signum)
{std::cout<<"我是进程:"<<getpid()<<",我自己给自己发送了"<<signum<<"号信号"<<std::endl;sleep(1);
}
int main()
{signal(3,handle);while(true){std::cout<<"我是进程:"<<getpid()<<",我在等待"<<std::endl;sleep(1);raise(3);}return 0;
}

abort
 

发送6号信号给自己来结束进程(就算自定义了6号信号也一样会退出)

#include<iostream>
#include<unistd.h>
#include<signal.h>
void handle(int signum)
{std::cout<<"我是进程:"<<getpid()<<",我收到了"<<signum<<"号信号"<<std::endl;
}
int main()
{signal(6,handle);//或者写SIGABRT(abort发送的6号信号的宏定义)while(true){std::cout<<"我是进程:"<<getpid()<<",我在等待"<<std::endl;sleep(1);abort();}return 0;
}

由软件条件产生信号

主要介绍alarm函数与SIGALRM信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
//返回值为0或者之前设定的闹钟还剩下的时间
//没有设定过闹钟就返回0//设定过闹钟有两种返回情况
//如果没有修改默认动作,那么就说明这里一定不是由信号产生的,返回之前设定的闹钟剩下的时间
//修改过默认动作的话,如果是在SIG_ALRM信号里再次调用,那么之前设定的闹钟剩下的时间就肯定为0了,返回值为0


也就只有一个作用:定时

设定一下多少秒后发送SIGALRM信号,默认动作为结束当前进程

使用方法有两种:

1.设定seconds不为0,那么就设定一个闹钟

2.设定second为0,那么就取消以前设定的闹钟

puase函数

int pause()
//将进程挂起(暂停)直到接收到一个信号才重新唤醒进程
//返回值总是-1,并且会设置错误码,表示进程被信号中断

我们在这里用pause和alarm函数来测试一下

测试

#include<iostream>
#include<unistd.h>
#include<signal.h>
void handle(int signum)
{std::cout<<"进入alarm自定义动作,打断挂起"<<std::endl;
}
int main()
{alarm(5);signal(SIGALRM,handle);std::cout<<"即将进入pause被挂起"<<std::endl;pause();std::cout<<"被alarm信号解除pause的挂起状态"<<std::endl;return 0;
}

如何理解软件条件
 

在操作系统中,信号的软件条件指的是由软件内部状态或特定软件操作触发的信号产生机制。这些条件包括但不限于定时器超时(如alarm函数设定的时间到达)、软件异常(如向已关闭的管道写数据 产生的SIGPIPE信号)等。当这些软件条件满足时,操作系统会向相关进程发送相应的信号,以通知进程进行相应的处理。简而言之,软件条件是因操作系统内部或外部软件操作而触发的信号产生

硬件异常产生信号
 

硬件异常被硬件以某种⽅式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产⽣异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
 

由此可以确认,我们在C/C++当中除零,内存越界等异常,在系统层面上,是被当成信号处理的
 

子进程退出core dump

#include <iostream>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
int main()
{if (fork() == 0){sleep(1);int* now=nullptr;*now=1;exit(0);}int status = 0;waitpid(-1, &status, 0);printf("exit signal: %d, core dump: %d\n", status & 0x7F, (status >> 7) & 1);return 0;
}

 正常退出,后8为表示退出码

非正常退出(被信号杀死),前7为表示信号编号,第8位表示core dump标志

Core Dump
 

SIGINT的默认动作为终止进程并且core dump

解释什么是Core Dump。当⼀个进程要异常终止时,可以选择把进程的用户空间内存数据全部
保存到磁盘上,文件名通常是core,这叫做Core Dump。
进程异常终止通常是因为有Bug,⽐如非法内存访问导致段错误,事后可以用调试器检查core文件以
查清错误原因,这叫做 Post-mortem Debug (事后调试)

⼀个进程允许产生多大的 core 文件取决于进程的 Resource Limit (这个信息保存在PCB
中)。默认是不允许产⽣ core 文件的,因为 core ⽂件中可能包含用户密码等敏感信息,不安全。
 

在开发调试阶段可以⽤ ulimit 命令改变这个限制,允许产生 core 文件。⾸先⽤ ulimit 命令
改变 Shell 进程的 Resource Limit ,如允许 core 文件最大为 1024K: $ ulimit -c
1024

 保存信号

信号其他相关常见概念
 

实际执行信号的处理动作称为信号递达(Delivery)

从信号产生到抵达之前的状态称为信号未决(Pending)

进程可以选择阻塞(Block)某个信号

信号被阻塞就不会被递达,保持在未决状态,除非进程解除阻塞,才能执行递达工作

注意:阻塞与忽略不同,阻塞是收到了信号但不执行动作,忽略是收到了信号并执行了动作,只不过动作本身为忽略

在内核中的表示

如上图,每个信号都有两个标志位block与pending,还有一个信号处理函数handler

当信号产生时就会设置pending标志位,决定执行信号时再清空pending标志位

清空pending的具体步骤为:

某信号没有被阻塞并且轮到了该信号->取出信号->清空pending->执行动作

我们以图中的三种情况为例:

1.SIGHUP信号没有产生也没有阻塞,它递达时将会执行SIG_DFL(即默认处理方法)

2.SIGINT信号产生了,并且被阻塞,那么该信号就会保持在未决状态,直到信号阻塞被进程解除,处理方法为SIG_IGN(即信号忽略)

3.SIGINT信号没有产生,但是被阻塞了,当信号产生时,信号就会一直被阻塞,保持在未决状态。处理方法为自定义方法sighandler

如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信
号⼀次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计⼀次,而实时信号在递达之
前产⽣多次可以依次放在⼀个队列⾥。本章不讨论实时信号。
 

sigset_t
 

从上图来看,每个信号只有⼀个bit的未决标志,非0即1,不记录该信号产⽣了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储, sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“⽆效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。下⼀节将详细介绍信号集的各种操作。阻塞信号集也叫做当前进程的信号屏蔽字,这⾥的“屏蔽”应该理解为阻塞而不是忽略。
 

信号集操作函数
 

sigset_t类型对于每种信号⽤⼀个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些
bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调⽤以下函数来操作sigset_t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的。
 

#include <signal.h>//初始化信号集的所有数据,使其中所有信号的bit位置0,该信号集不会包含任何有效信号
int sigemptyset(sigset_t *set);//初始化信号集的所有数据,使其中所有信号的bit位置1,表示该信号集启用所有系统支持的信号
int sigfillset(sigset_t *set);//为信号集增加某个信号
int sigaddset(sigset_t *set, int signo);//删除某个信号
int sigdelset(sigset_t *set, int signo);//判断某个信号是否存在于信号集中
int sigismember(const sigset_t *set, int signo);

上面的四个函数都是成功返回0,失败返回-1。

sigismember是一个bool函数,存在返回1,不存在返回0,出错返回-1

sigprocmask
 

#include <signal.h>//读取或更改进程的信号屏蔽字(阻塞信号集)
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);//返回值:若成功则为0,若出错则为-1

简单说下参数,how指示应该如何处理信号屏蔽字

如果set是非空指针,那么就和how一起进行修改进程的信号屏蔽字

如果oset是非空指针,那么就把修改前的信号屏蔽字带出来

如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中⼀
个信号递达。


sigpending

#include <signal.h>
int sigpending(sigset_t *set);//读取当前进程的未决信号集,通过set参数传出。
//调⽤成功则返回0,出错则返回-1


测试

我们使用上面学习的几个函数进行一点测试

#include <iostream>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
void PrintPending(sigset_t set)
{std::cout << "curr process[" << getpid() << "]pending: ";for (int i = 31; i >= 1; --i)std::cout << sigismember(&set, i);std::cout << std::endl;
}
void handler(int signum)
{std::cout << signum << "号信号被递达!" << std::endl;std::cout << "-------------------------------" << std::endl;sigset_t pending;sigpending(&pending);PrintPending(pending);std::cout << "-------------------------------" << std::endl;
}
int main()
{signal(2, handler);sigset_t block_set, old_set;sigemptyset(&block_set);sigemptyset(&old_set);sigaddset(&block_set, 2);sigprocmask(SIG_BLOCK, &block_set, &old_set);int cnt = 5;while (true){sigset_t pending;sigpending(&pending);PrintPending(pending);cnt--;if (cnt == 0){std::cout << "解除对2号信号的屏蔽!!!" << std::endl;sigprocmask(SIG_SETMASK, &old_set, &block_set);}sleep(1);}
}

从这里我们也可以看出,pending标志位是在执行动作之前就已经被清空了

捕捉信号
 

信号处理流程

 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。

 上文已经解释的很清楚了,我们在这里再次解释下信号处理的全部过程

流程

1.首先,由于中断、异常、系统调用等原因从用户态进入内核态

2.内核态处理完异常之后处理可以执行动作的信号(没有信号需要处理那么就单纯恢复上下文继续向下执行)

3.如果是自定义信号处理函数,那么就由内核态转为用户态执行信号处理函数(如果不是自定义信号那么就视信号类型而定,有些信号的默认动作可以在内核态执行,而有些还是需要返回用户态执行,因为默认动作保存在内核里而不是在用户写的代码里)

4.执行完自定义函数之后,信号处理函数返回时会调用特殊系统调用再次进入内核(因为要恢复上下文,继续执行之前还没执行完的程序)

5.回到内核后,判断信号是否全部处理完,没有处理完,则继续按照上面的流程进入用户态执行信号处理函数。全部处理完之后,恢复上下文,进入用户态执行接下来的程序

总的来说,执行自定义信号处理函数就是:

1.进入内核获取信号

2.返回用户态执行函数

3.执行完后返回内核恢复上下文

4.返回用户态继续执行

sigaction
 

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

这个函数可以看作是“加强版”的signal函数,因为他的功能更强大

struct sigaction {void (*sa_handler)(int); // 信号处理函数void (*sa_sigaction)(int, siginfo_t *, void *); // 用于支持信号的附加信息sigset_t sa_mask; // 在信号处理函数执行期间需要屏蔽的信号集合int sa_flags; // 信号处理的标志void (*sa_restorer)(void); // 已废弃,不要使用
};

oact,即old action,将旧的信号处理动作带出来,为空则不带回

act,即action,放入一个新的信号处理动作,为空则不修改

我们主要介绍下sa_handler与sa_mask

sa_handler

信号处理动作,与signal函数相同,是一个返回值为空,参数为int的函数指针

sa_mask

执行信号处理函数期间需要屏蔽的信号集

原理就是

1.在收到信号,执行信号处理函数之前,保存原先的信号屏蔽字

2.将当前进程信号屏蔽字与我们传入的sa_mask进行'或'操作,也就是增加一些信号屏蔽字

3.执行信号处理函数

4.信号处理函数结束后,使用事先保存好的信号屏蔽字来进行恢复

硬件中断
 

由外部设备触发的,中断系统运行流程,叫做硬件中断

中断向量表是操作系统的一部分,一启动就加载到了内核,保存了各种中断的处理方法

总结这张图:

1.外部设备发起终端

2.中断控制器收到中断,通知cpu

3.cpu知道有中断,向中断控制器获取中断号,并保护现场

4.cpu根据中断号查中断向量表,执行对应的方法

5.执行完中断之后,恢复现场,继续之前的工作


时钟中断
 

定时触发的设备,定期产生时钟中断

位于操作系统最底下的中断,操作系统所有的操作都要按照时钟中断来执行

包括轮询、调度、定时

操作系统在时钟中断的推动下进行定时调度

//以下为操作系统调度的模拟void handler(int signum)
{调度
}int main()
{//时钟中断定期产生,操作系统是个死循环,定期产生的时钟中断推着操作系统进行调度while(1){}
}

操作系统本质就是个死循环

我们需要什么中断,需要什么方法,就向中断向量表里面加就可以了

最终都会交给cpu来进行执行

软中断
 

软件也有自己的软中断

为了让操作系统⽀持进行系统调用,CPU也设计了对应的汇编指令(int或者syscall),可以让CPU内
部触发中断逻辑

不同的指令代表着不同的软中断处理方法,只不过这些指令产生的中断统称为软中断

就像上面的键盘,显示等等也可以统称为硬件中断

我们在使用的时候最终都是通过中断来让cpu执行我们的方法,只不过linux的C标准库已经帮我们把这些软中断指令封装好了

缺页中断?内存碎片处理?除零野指针错误?

最后全都会被转化为cpu的软中断进行处理,走中断处理流程

理解内核态与用户态

用户区在[0,3]GB

内核区在[3,4]GB

上面总结一下就是级别的问题

内核权限高于用户,内核可以访问用户,用户却不能直接访问内核

用户可以采用软中断指令触发系统调用,cpu保存用户态的上下文数据,进入权限更高的内核态

内核可以访问用户的数据,实际上就是内核态可以访问进程的地址空间拿到数据,然后在内核态执行系统调用方法,将运行结果交给进程

这样子就不是多个进程主动查找操作系统,而是操作系统主动去找进程,这样就可以让多个进程找到同一个操作系统了

volatile

这个关键字的目的主要是为了保证数据必须严格读取内存中最新的值

主要是为了应对优化的情况,不优化的话数据默认就是从内存中读取最新的值

但是一旦开启优化,编译器就会出于减少访问内存的次数提升效率的目的导致某些情况下获取到的数据可能不是最新的

例如:

1.多线程情况下,相当于多个程序对同一个数据进行修改,那么我们开启优化就会导致数据不一致的情况

2.信号直接修改数据的值,这样的话优化后程序又不读取内存最新的值就会导致同样的数据不一致情况

例子

我们不加volatile关键字

#include <stdio.h>
#include <signal.h>
int flag = 0;
//volatile flag=0;
void handler(int sig)
{printf("chage flag 0 to 1\n");flag = 1;
}
int main()
{signal(2, handler);while (!flag);printf("process quit normal\n");return 0;
}

不开优化

开启优化

^Cchage flag 0 to 1
^Cchage flag 0 to 1
^Cchage flag 0 to 1

加上关键字

^Cchage flag 0 to 1
process quit normal

volatile作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该
变量的任何操作,都必须在真实的内存中进行操作
 


http://www.hkcw.cn/article/cJxNihusEe.shtml

相关文章

AWTK 嵌入式Linux平台实现多点触控缩放旋转以及触点丢点问题解决

前言 最近涉及海图的功能交互&#xff0c;多点触摸又开始找麻烦。 在PC/Web平台awtk是通过底层的sdl2库来实现多点触摸&#xff0c;但是在嵌入式Linux平台&#xff0c;可能是考虑到性能原因&#xff0c;awtk并没有采用sdl库来做事件处理&#xff0c;而是自己实现一个awtk-lin…

电脑重装或者开机出现错误

电脑重装或出现如下错误&#xff0c;遇到的错误信息表明在安装Windows时计算机意外重启或遇到错误&#xff0c;导致安装无法继续&#xff0c;怎么解决&#xff0c;以以下这个电脑举例 按shiftf10出现窗口 输入regedit回车 依次找到以下路径 HKEY_LOCAL_MACHINE/SYSTEM/SETUP…

印军方首次证实有战机被击落 损失数目不详引发关注

印度军方首次证实其在5月份与巴基斯坦的冲突中损失了数量不明的战斗机,同时表示这场为期四天的冲突从未接近核战争爆发点。印度国防参谋长阿尼尔乔汉在新加坡出席香格里拉对话会期间接受采访时说:“重要的并非飞机被击落,而是它们为什么会被击落。”他否认了巴基斯坦方面关于…

为什么当年梅西、内马尔、姆巴佩在巴黎拿不到欧冠,现在球队没有他们反而能夺冠? 青春风暴的胜利

北京时间6月1日凌晨,欧洲冠军联赛决赛落下帷幕。巴黎圣日耳曼队以5比0战胜国际米兰,历史上首次夺得欧冠冠军,并实现了赛季三冠王(法甲、法国杯、欧冠)。多年来,“大巴黎”一直是石油足球和金元足球的代表,坚持“超级巨星路线”,但无论是姆巴佩、梅西还是内马尔都未能带…

【C++】 类和对象(上)

1.类的定义 1.1类的定义格式 • class为定义类的关键字&#xff0c;后跟一个类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省 略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或 者成员函数。…

Spring之循环依赖源码解析

在学习Spring源码流程解析之前&#xff0c;首先要清楚什么是循环依赖&#xff0c;怎么解决循环依赖再去跟着源码学习一遍&#xff0c;更能加深印象。Mark

贾乃亮晒与甜馨端午节合照 父女笑容神同步

5月31日,贾乃亮在社交媒体上晒出与女儿甜馨的端午节合照,并提问大家猜猜他和甜馨吃的是甜粽还是咸粽。有网友评论说,两人的脸看起来非常相似,就连笑容都很像。甜馨,本名贾云馨,2012年10月23日出生于北京,是演员贾乃亮与李小璐的女儿。2014年4月,她与父亲一起参加了明星…

外交部深夜发声:勿要玩火 坚决反对美方消极言论

6月1日,外交部发言人就美国防长赫格塞思在香格里拉对话会上的涉华消极言论回答了记者提问。有记者问,5月31日,美国防长赫格塞思在香格里拉对话会上发表演讲,大肆渲染中国威胁,并就涉台、南海等问题发表消极言论。对此,中方表示强烈不满和坚决反对,已向美方提出严正交涉。…

零跑汽车5月交付量45067辆 增速超148%

6月1日,据零跑汽车公众号消息,2025年5月,零跑汽车单月交付量45067辆,增速超148%。连续三个月稳居造车新势力领先地位。责任编辑:zx0176

债市全年低点出现在何时 8月和12月规律探析

自2019年降息周期以来,10年国债收益率的全年低点容易出现在8月和12月。这背后的原因可以从基本面、政策面、资金面及机构行为等角度进行分析。从基本面来看,2019年以来,从第二季度开始,GDP增速容易低于全年预期目标,PMI也容易进入下行或低于枯荣线的阶段。而政策发力可能使…

中方回应美防长涉华消极言论 坚决反对美方挑衅挑拨

6月1日,外交部发言人针对美国防长赫格塞思在香格里拉对话会上的涉华消极言论进行了回应。有记者提问称,5月31日,赫格塞思在香格里拉对话会上发表演讲,渲染中国威胁,并就台湾、南海等问题发表负面言论。发言人在回答中指出,赫格塞思无视地区国家追求和平与发展的愿望,兜售…

孟维瞻:马斯克挥一挥衣袖,带走了什么,留下了什么?

【文/观察者网专栏作者 孟维瞻】马斯克离开白宫了。尽管这是一个早就预定好的结局,但在他和特朗普两人关系热火朝天的时候,大家不是没有想过另一种结局。当然,也有很多人在期待,两个人如胶似漆的蜜月期之后是否会反目成仇。如今看来,虽然说不上是反目成仇,至少也是话不投…

南航通报飞机起飞后突然返航 电池冒烟险情妥善处置

5月31日13时许,中国南方航空发布通报称,当天CZ6850杭州飞往深圳的航班上,一名旅客携带的相机电池和充电宝出现冒烟情况。乘务组迅速采取措施,妥善处置,及时排除了安全风险。为确保乘客安全,机组决定立即返航,航班在起飞15分钟后安全降落。航空公司积极做好后续服务保障工…

浙江暴雨将持续至明天上午 需防范次生灾害

不怕七月半鬼,最怕端午水。5月31日,西湖景区一景被拍摄下来。当天下午,浙西北地区开始下雨。到晚上8时,杭州、湖州累计雨量超过了14毫米,单站点最大雨量为52.9毫米,出现在临安区龙塘山。省气象台在16时20分发布暴雨警报:受西南暖湿气流和弱冷空气影响,5月31日夜里至6月…

奇瑞董事长说降价是被绑架的 反内卷呼声高

汽车行业近期出现了对“反内卷”的强烈呼声。在5月31日的2025(第三届)未来汽车先行者大会上,奇瑞汽车董事长尹同跃针对车市价格战表示,“‘价格战’是我最不喜欢的一个词,因为我是被绑架的。”他提到销售团队会告诉他竞争对手已经采取了降价措施,这让他感到非常痛苦和违背…

go|context源码解析

文章目录 Context接口Deadline()Done()Err()Value() canceler接口ctxemptyCtxcancelCtxtimerCtxvalueCtx 基本使用cancelCtxvalueCtx 首先看一下源码对“context”的描述&#xff0c; When a Context is canceled, all Contexts derived from it are also canceled. 当一个Cont…

香港中乐团六月京津巡演 携多位国际艺术家献演

被誉为“民乐翘楚”的香港中乐团受邀于6月13至18日赴北京及天津举行三场“阎惠昌与香港中乐团2025”内地巡演。乐团荣幸获得中华人民共和国香港特别行政区政府驻北京办事处&#xff0c;及巡演赞助商李锦记国际控股有限公司全力支持&#xff0c;将于北京艺术中心的《笙与管风琴的…

[yolov11改进系列]基于yolov11引入高效上采样卷积块EUCB的python源码+训练源码

【EUCB介绍】 论文介绍 题目 EMCAD:Efficient Multi-scale Convolutional Attention Decoding for Medical Image Segmentation 论文地址 https://arxiv.org/pdf/2405.06880 创新点 多尺度卷积解码器&#xff1a;提出了一种高效的多尺度卷积注意力解码器&#xff08;EMCAD&a…

oscp练习PG Monster靶机复现

端口扫描 nmap -A -p- -T4 -Pn 192.168.134.180 PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.41 ((Win64) OpenSSL/1.1.1c PHP/7.3.10) |_http-server-header: Apache/2.4.41 (Win64) OpenSSL/1.1.1c PHP/7.3.10 | http-methods:…

樊振东莫雷加德成为队友 共迎新挑战

6月1日,萨尔布吕肯俱乐部宣布樊振东加盟德甲联赛。在萨尔布吕肯乒乓球甲级俱乐部的官宣消息中,樊振东表示他非常期待在萨尔布吕肯和德甲的新挑战,体验新的环境,并与球队一起赢得更多胜利。球队经理透露,这一切来得如此令人惊讶且迅速,他们仍然难以完全相信。但这是现实—…