欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

信号的产生

程序员文章站 2022-07-12 10:31:10
...

进程信号:
信号生命周期:信号的产生—>信号的注册—>信号的阻塞(屏蔽)—>信号的注销—>信号的处理
信号列表:知道有哪些信号,并且对应了哪些操作
kill :可以杀死一个进程,但并不是为了杀死一个进程设计的,而是为了给某一指定进程发送一个信号
信号的产生
kill杀死进程的时候,默认给这个进程发送的是哪个信号?


在默认情况下,采用编号为15的TERM信号。TERM信号将终止所有不能捕获该信号的进程。对于那些可以捕获该信号的进程就要用编号为9的kill信号,强行“杀掉”该进程。

Linux下一共有62个信号(32,33没有),并且分了两类:1-31 是非可靠信号(非实时信号):1-31号信号是继承于unix而来,每一个信号 都对应了一个指定事件;非可靠是指信号有可能丢失,如果有相同的信号已经注册到这个进程没有被处理,那么接下来相同信号就会丢掉;
34-64 是可靠信号(实时信号):信号不会丢失。
信号的功能:实际上就是为了通知进程发生了哪些事件,应该怎么处理,信号实际也可以归为一类进程间通信。
中断:打断当前操作,然后去处理这个中断的事件
硬件中断:ctrl+c(中断前台进程)或者ctrl+\(退出前台进程)
软件中断:linux下的信号实际是软中断
信号与信号量区别:

信号实际是一个软中断,用于通知进程发生了某些事件,实际信号也可以算作进程间通信的方式之一。因为可以在一个进程通过给另一个进程发生信号,来告诉另一个进程发生了什么事。
产生信号:

1.硬件中断(ctrl+C),对于进程来说是软中断;

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

int main()
{   
        while(1)
        {   
                printf("pick\n");
                sleep(1);
        }   
        return 0;
}

crtl+c是硬件中断,操作系统就会让前台进程退出,相当于2号信号SIGINT;
前台进程是一直运行在终端上,如果终端有进程正在运行,按命令没反应
信号的产生
后台进程:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{        
    if(fork()>0)       
     {                   
         exit(0);       
     }           
     while(1)       
      {                  
       printf("pick\n");                
       sleep(1);        
       }           
       return 0;
}

信号的产生
在后台进程中输入ls等命令有效,但是ctrl+c不能使进程结束,需要用kill命令使进程退出。
信号的产生
2.硬件异常 (段错误:内存访问错误SIGSEGV);

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
        char *ptr=NULL;
        memcpy(ptr,"hello",10);
        return 0;
}

信号的产生
段错误是11号信号SIGSSEGV。
3.接口调用发送信号 (kill命令);

kill可以杀死一个进程,但并不是为了杀死一个进程设计的,而是为了给某一指定进程发送一个信号。

4.软件条件产生(kill函数、raise函数、alarm函数、sigqueue函数);


信号的产生

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

int main()
{
        kill(getpid(),SIGINT); ///给自己发送SIGINT中断信号
        while(1)
        {   
                printf("pick\n");
                sleep(3);
        }   
        return 0;
}

信号的产生

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

int main()
{
        raise(SIGABRT);//给自己发送SIGABRT信号
        while(1)
        {   
                printf("pick\n");
                sleep(3);
        }   
        return 0;
}

信号的产生

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

int main()
{
        sigqueue(getpid(),SIGPIPE,(union sigval)0);
        while(1)
        {    
                printf("pick\n");
                sleep(3);
        }   
        return 0;
}

信号的产生

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
int main(){        
    int ret=alarm(5);//ret=0        
	sleep(1);//睡了一秒        
   ret=alarm(3);//返回上一个定时器剩余时间,由于睡了一秒还剩4秒          printf("ret:%d\n",ret);        
  while(1)       
  {                   
    sleep(1);       
  }        
  return 0;  
 }

信号的产生
Core Dump(核心转储)

  • 程序异常的时候会记录一个核心转储文件,在这个文件中记录的是程序的运行数据。当一个程序异常崩溃时,而这个错误可能只是偶尔发生,那么这种错误将非常难定位,因为我们也不知道到底什么时候才会崩溃。因此这个转储文件就十分重要,因为它可以帮我们使用gdb调试查看,定位错误。
  • gdb运行可执行程序,然后在gdb中使用命令:core -file +转储文件名称(如core.3996)来加载程序的运行数据,然后可以定位错误。
  • 但是程序的核心转储功能默认是关闭的,转储文件大小默认是0,因为运行数据中可能会有安全性信息,以及文件增多会占用资源。
  • 查看转储文件大小或设置:
    ulimit -c (查看);
    ulimit -c size (通过设置转储文件大小来开启转储功能)