11.Linux进程信号(一) - 实践
2025-12-03 20:33 tlnshuju 阅读(6) 评论(0) 收藏 举报
一.信号快速认识




二.信号的产生
1.键盘产生




那么,我们怎么结束我们的命令行呢?
方式一.

方式二.


ctrl + c只能杀掉前台进程,没法杀死后台进程
![]()
2.signal接收信号


这个signal方法,能够修改我们对应的信号所对应的方法
我们只看1-31号信号(普通信号),32-64号为实时信号
a.SIGINT信号
ctrl + c表示的是2号信号(SIGINT)

#include
#include
#include
void Handler(int signo)
{
//当对应的信号被触发,内核会将对应的信号进行编号,传递给自定义方法
std::cout << "Get a signal,signal number is : " << signo << std::endl;
}
int main()
{
signal(SIGINT,Handler);//默认终止 -> 执行自定义方法: Handler
while(true)
{
std::cout << "hello world" << std::endl;
sleep(1);
}
return 0;
}


ctrl + \也能终止进程

所以,我们就知道了,对于我们的信号有默认的处理方式,并且我们还可以设置相关的信号处理方式
对于默认的处理方式,我们可以使用man 7 signal进行查看

b.SIGQUIT信号(ctrl + \)
#include
#include
#include
void Handler(int signo)
{
//当对应的信号被触发,内核会将对应的信号进行编号,传递给自定义方法
std::cout << "Get a signal,signal number is : " << signo << std::endl;
}
int main()
{
signal(SIGQUIT,Handler);//默认终止 -> 执行自定义方法: Handler
while(true)
{
std::cout << "hello world" << std::endl;
sleep(1);
}
return 0;
}


![]()
c.问题一
signal为啥不放在循环里面?
signal只要被设置一次即可,后续如果收到该信号,就能直接触发handler
d.问题二
signal: 如果没有产生2或3号信号呢?
那我们的handler就永远都不调用
3.无法捕捉的信号
如果我们将所以的信号全部都进行捕捉,那是不是我们对应的进程就永远都杀不死了?
#include
#include
#include
void Handler(int signo)
{
//当对应的信号被触发,内核会将对应的信号进行编号,传递给自定义方法
std::cout << "Get a signal,signal number is : " << signo << std::endl;
}
int main()
{
for(int signo = 1;signo < 32;signo++)
{
signal(signo,Handler);//默认终止 -> 执行自定义方法: Handler
std::cout << "自定义捕捉信号: " << signo << std::endl;
}
while(true)
{
std::cout << "hello world" << std::endl;
sleep(1);
}
return 0;
}


4.理解信号处理
a.软件



然后根据我们的位图,就能确定要执行的是哪一个函数处理方法
b.硬件
![]()
当我们的键盘按下的时候,我们的键盘会向操作系统发送硬件中断

有了硬件中断,所以我们发现硬件和OS能并行执行了



5.指令产生信号


6.kill函数


#include
#include
#include
#include
#include
void Usage(std::string proc)
{
std::cout << "Usage: " << proc << " signumber processid" << std::endl;
}
// ./mykill 9 1234
int main(int argc,char* argv[])
{
if(argc != 3)
{
Usage(argv[0]);
exit(1);
}
int signumber = std::stoi(argv[1]);
pid_t id = std::stoi(argv[2]);
int n = ::kill(id,signumber);
if(n < 0)
{
perror("kill");
exit(2);
}
exit(0);
return 0;
}
这样我们的程序就和命令行的使用方式差不多了
这里我们启动了一个cat进程



7.raise函数

#include
#include
#include
#include
#include
// ./mykill 9 1234
int main()
{
int cnt = 5;
while(true)
{
std::cout << "hahaha alive" << std::endl;
cnt--;
if(cnt <= 0)
{
raise(9);
}
sleep(1);
}
return 0;
}

8.abort函数

#include
#include
#include
#include
#include
// ./mykill 9 1234
int main()
{
int cnt = 5;
while(true)
{
std::cout << "hahaha alive" << std::endl;
cnt--;
if(cnt <= 0)
{
abort();
}
sleep(1);
}
return 0;
}


三.信号产生的软件条件


本质上还是操作系统进行信号发送的


#include
#include
#include
#include
#include
int main()
{
alarm(1);
int number = 0;
while(true)
{
printf("count: %d\n",number++);
}
return 0;
}

我们这1秒钟才跑5-6万次,是不是太慢了?
#include
#include
#include
#include
#include
int number = 0;
void die(int signumber)
{
printf("get a sig : %d, count : %d\n",signumber,number);
exit(0);
}
int main()
{
alarm(1); // 我们自己,会在1S之后会收到一个SIGALRM信号
signal(SIGALRM,die);
while(true)
{
number++;
}
return 0;
}

但是,我们看到了这个数累加的比上面多了很多,这是为啥呢?




#include
#include
#include
#include
#include
int main()
{
alarm(10);
sleep(4);
int n = alarm(0);//取消闹钟
std::cout << "n: " << n << std::endl;
return 0;
}

当我们不想要之前的闹钟了,我们可以考虑重置闹钟,返回值就是之间的差值
四.设计一个定时器完成对应任务
#include
#include
#include
#include
#include
#include
#include
using func_t = std::function;
int gcount = 0;
std::vector gfuncs;
void handler(int signo)
{
for(auto& f : gfuncs)
{
f();
}
std::cout << "gcount : " << gcount << std::endl;
}
int main()
{
gfuncs.push_back([](){
std::cout << "我是一个日志任务" << std::endl;
});
gfuncs.push_back([](){
std::cout << "我是一个下载任务" << std::endl;
});
gfuncs.push_back([](){
std::cout << "我是一个mysql任务" << std::endl;
});
alarm(1);
signal(SIGALRM,handler);
while(true)
{
gcount++;
}
return 0;
}


闹钟是一次性的闹钟,超时自动取消
#include
#include
#include
#include
#include
#include
#include
using func_t = std::function;
int gcount = 0;
std::vector gfuncs;
void handler(int signo)
{
for(auto& f : gfuncs)
{
f();
}
std::cout << "gcount : " << gcount << std::endl;
alarm(1);
}
int main()
{
gfuncs.push_back([](){
std::cout << "我是一个日志任务" << std::endl;
});
gfuncs.push_back([](){
std::cout << "我是一个下载任务" << std::endl;
});
gfuncs.push_back([](){
std::cout << "我是一个mysql任务" << std::endl;
});
alarm(1);
signal(SIGALRM,handler);
while(true)
{
gcount++;
}
return 0;
}


#include
#include
#include
#include
#include
#include
#include
using func_t = std::function;
int gcount = 0;
std::vector gfuncs;
void handler(int signo)
{
for(auto& f : gfuncs)
{
f();
}
std::cout << "gcount : " << gcount << std::endl;
alarm(1);
}
int main()
{
gfuncs.push_back([](){
std::cout << "我是一个日志任务" << std::endl;
});
gfuncs.push_back([](){
std::cout << "我是一个下载任务" << std::endl;
});
gfuncs.push_back([](){
std::cout << "我是一个mysql任务" << std::endl;
});
alarm(1);
signal(SIGALRM,handler);
while(true)
{
pause();
std::cout << "我醒来了..." << std::endl;
gcount++;
}
return 0;
}


如果将我们的 alarm 切换成 硬件中断 ,这样就是操作系统的原理

五.异常(信号产生的一种方式)
#include
#include
#include
#include
#include
#include
#include
int main()
{
int* p = nullptr;
*p = 100;
while(true)
{
}
return 0;
}
很明显,我们这个程序出现了段错误(一般是野指针)



#include
#include
#include
#include
#include
#include
#include
int main()
{
int a = 10 / 0;
while(true)
{
}
return 0;
}


#include
#include
#include
#include
#include
#include
#include
void handler(int signo)
{
std::cout << "get a signo: " << signo <





但是,我们的进程为啥没有退出呢?

OS不会处理Eflags,只会处理信号,所以Eflags里面的标志位一直都是1,所以就是死循环

这个错误也一直存在,所以也会死循环

六.Core和Term的区别

1.Core
核心转储




#include
#include
#include
#include
#include
#include
#include
int main()
{
int a = 10 / 0;
return 0;
}

环境不一样,生成的core就不一样(可能是core.xxx)
这里默认将core进行关闭的,但是如果进程出错了,那么就会重启(这样就一直出错,一直重启),那么哦我们的磁盘上很容易被打满core.xxx
我们的新一点的服务器,只会生成core(避免一直生成core.xxx,一直只有一个)
BIN=timer
CC=g++
SRC=$(shell ls *.cc)
OBJ=$(SRC:.cc=.o)
$(BIN):$(OBJ)
$(CC) -o $@ $^ -std=c++11
%.o:%.cc
$(CC) -c $< -g -std=c++11
.PHONY:clean
clean:
rm -f $(BIN) $(OBJ)
我们,要加上对应的-g选项,支持debug


我们可以先出错,然后再利用核心转储,进行事后调试


第八个比特位是core dump标志位
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
if(fork() == 0)
{
sleep(1);
int a = 10;
a /= 0;
exit(0);
}
int status = 0;
waitpid(-1,&status,0);
printf("exit signal : %d, core dump: %d\n",status&0x7F,(status>>7)&1);
return 0;
}


服务器core功能关闭,我们的代码也不能进行获得core dump标志位
2.Term
Term就是表示我们正常的退出,不需要进行debug


浙公网安备 33010602011771号