linux c信号

一、什么是信号
   1、 信号就是软件中断,很多的程序都需要处理信号。信号提供了一种处理异步事件的机制。
    例如:当用户在终端下运行一个程序时,用户在键盘键入一个中断键(CTRL+C),则会通过信号机制终止一个正在运行的程序。
   
   2、每一个信号都有自己独特的名字。这些名字都是以SIG开头的。例如中断信号SIGINT.在linux下输入shell命令kill -l可以看到linux所支持的所有的信号名称以及信号的编号。其中1号到32号(32号信号用户是不能使用的)信号都是继承UNUX系统的信号。其余的是linux系统根据POSIX标注定义的信号。

   3、在编写信号程序时,必须加上头文件<signal.h>。事实上,信号的定义的定义在另外的一个头文件中,但是该头文件又包含在<signal.h>中。
     大家可以查看头文件/usr/include/signal.h 发现里边有一句include <bits/signum.h>,然后再查看头文件/usr/include/bits/signum.h  大家会发现信号的定义都在这里边.

二、信号产生的方式
 1、用户按键,如用户按下了CTRL+C组合键
 2、硬件异常,如除数为0,无效内存引用
 3、进程调用kill函数将信号发送给一个进程或者进程组,限制条件是:接受信号进程和发送信号进程的所有者必须相同。或者发送信号的进程的所有者是超级用户
 4、调用命令kill,实际上此命令是kill函数的接口
 5、检测到某种软件条件已经发生。例如 SIGPIPE(管道的读进程已经终止后,另一个进程写此管道时产生)
 
 当产生信号时,内核通常会在进程表中设置一个某种形式的标志,这就是所谓的向进程发送了一个信号。

三、进程的处理
 1、捕捉信号,可以指定信号的处理函数,当捕捉的信号时自动执行此函数
 2、忽略信号,除了SIGKILL和SIGSTOP,因为它们向超级用户提供了使进程终止或停止的方法。另外忽略了由某些硬件异常产生的信号(如无效内存引用),则进程运行的行为是不可预测的。
 3、按照系统默认的方式处理,大部分信号的默认处理方式是终止进程,

四、信号的捕捉和处理
 1、signal函数 -- 信号机制最简单的接口,用来设置进程在接受到信号时候的动作
  在shell下输入man signal查看函数原型
   

#include <signal.h>
typedef void (*sighandler_t)(int);    //定义函数指针类型
sighandler_t signal(int signum, sighandler_t handler);


signum为信号的编号
handler为信号处理函数
执行成功是返回信号处理函数指针,不成功时返回-1

举例如下:


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

/*信号处理函数*/
void handler_signal(int signo)
{
    printf("receive a signal\n");
    exit(0);
}


int main()
{
    signal(SIGINT,handler_signal); //进程接收到中断信号(SIGINT),执行handler_signal函数
    while(1);

    return 0;

}


编译、运行程序
当用户按下CTRL+C组合键时,程序退出,输出receive a signal

这就是一个简单的关于信号的函数

2、sigaction函数

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

sigaction函数用来检查或者设置进程在接收到信号时的动作。
signum为信号编号
act不为空指针,则为新的信号处理函数;
oldact不为空指针,则为旧的信号处理函数将储存在oldact中。


struct sigaction {
               void (*sa_handler)(int);
               void (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t sa_mask;
               int sa_flags;
               void (*sa_restorer)(void);
           };

sa_handler为信号处理函数的函数名
sa_sigaction也是信号处理函数的的函数名
sa_mask声明了一个信号集,在调用该信号捕捉函数之前,这一信号集要加入到进程的信号屏蔽字中。仅当从信号捕捉函数返回时再进行进程的信号屏蔽字复位。这样在调用信号处理程序时候就能阻塞某些信号。
sa_flags设置对信号处理的一些选项。

具体的sigaction结构体的介绍,在使用man手册中会又详细的介绍。

举个简单例子:

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

void signal_handler1(int sig)
{
    printf("I am signal_handler1\n");
    printf("receive a signal!\n");
    exit(0);
}

void signal_handler2(int sig)
{
    printf("I am signal_handler2\n");
    printf("receive a signal!\n");
    exit(0);
}

int main()
{
    struct sigaction sac1,sac2;
    sac1.sa_handler = signal_handler1;
    sac2.sa_handler = signal_handler2;
    sigaction(SIGINT,&sac1,NULL);//设置信号的处理函数,将信号SIGNAL和信号处理函数signal_handler联系起来


    //sigaction(SIGINT,&sac2,NULL);//重新设置信号的处理函数,将信号SIGNAL和信号处理函数signal_handler2联系起来

    while(1);    
    exit(0);
}

编译、运行,结果显示执行了signal_handler1函数。
sigaction(SIGINT,&sac2,NULL);注释去掉,重新编译运行,结果显示的是执行了signal_handler2
函数,
通过此例,说明sigaction函数可以设置信号处理函数,或者重新设置信号处理函数。

s i g a c t i o n函数的功能是检查或修改(或两者)与指定信号相关联的处理动作。此函数取代了U N I X早期版本使用的s i g n a l函数

  Int sigaction(int signo,const struct sigaction *act,struct sigaction *oact);

  参数:signo 要检测或修改动作的信号量

  Act 非空时,表示要修改的动作

  Oact非空时,返回处理该信号的原先动作

  结构体sigaction如下:

  struct sigaction {

  void (*sa_handler)();/*处理函数或SIG_IGN(忽略)或SIG_DFL(默认)*/

  sigset_t sa_mask; /*处理函数过程中被阻塞*/

  int sa_flags; /*标志位,对信号进程处理选项*/

  } ;

  举例

  #include<stdio.h>

  #include<stdlib.h>

  #include<sys/types.h>

  #include<sys/stat.h>

  #include<signal.h>

  void msg(int signo)

  {

  if(signo==SIGINT)

  printf("Get SIGINT!\n");

  }

  int main()

  {

  sigset_t sigset,oset;/*sigset存放屏蔽信号,oset保存当前屏蔽信号*/

  struct sigaction action1,action2;/*信号处理*/

  action1.sa_handler=msg;

  sigaction(SIGINT,&action1,&action2);

  sleep(2);

  raise(SIGINT);/*发送SIGINT信号*/

  }

  输出:

  Get SIGINT



五、kill和raise函数
     

  #include <sys/types.h>
  #include <signal.h>
  int kill(pid_t pid, int sig);
  int raise(int sig);

kill函数将信号发送给进程或者进程组,但是前提是:接受信号进程和发送信号进程的所有者必须相同,即发送者和接受者的有效ID必须相同。或者发送信号的进程的所有者是超级用户
raise将信号发送个自己

raise(int sif)等价于kill(getpid(),int sig)

kill的pid参数
pid > 0   将信号发送给pid进程
pid == 0  将信号发送给和发送信号进程属于同一进程组的所有进程(这些进程的组ID等于发送进程的必须相同)
pid < 0   将信号发送给其进程组ID等于pid的的绝对值的进程。
pid == -1 将信号发送给发送进程有权限向它们发送信号的系统上的所有进程。

注意:上述的所有进程组都不包含某些特殊的系统进程。

六、alarm和pause函数


#include <unistd.h>
 unsigned int alarm(unsigned int seconds);
 
int pause(void);


alarm函数可以设置一个计时器。当计时器超时时,产生一个SIGALRM信号。如果不捕捉或者忽略这个信号,则其默认的动作就是终止调用alarm函数的进程
每个进程只能设置一个闹钟时钟,如果在调用alarm时,以前己为该进程设置了闹钟时钟,并且没有超时,则返回返回以前的闹钟的余留值作为本次alarm函数调用的返回值。以前的闹钟时钟被新值替换。若以前没有设置闹钟时钟,则调用alarm时,返回0

pause函数使进程挂起,直到捕捉到了一个信号。只有在执行了一个信号处理函数,并且从其返回时,pause才返回,在这种情况下,pause返回-1,并且将errno设置为EINTR。
Signal
Description
SIGABRT
由调用abort函数产生,进程非正常退出
SIGALRM
用alarm函数设置的timer超时或setitimer函数设置的interval timer超时
SIGBUS
某种特定的硬件异常,通常由内存访问引起
SIGCANCEL
由Solaris Thread Library内部使用,通常不会使用
SIGCHLD
进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略
SIGCONT
当被stop的进程恢复运行的时候,自动发送
SIGEMT
和实现相关的硬件异常
SIGFPE
数学相关的异常,如被0除,浮点溢出,等等
SIGFREEZE
Solaris专用,Hiberate或者Suspended时候发送
SIGHUP
发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送
SIGILL
非法指令异常
SIGINFO
BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程
SIGINT
由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程
SIGIO
异步IO事件
SIGIOT
实现相关的硬件异常,一般对应SIGABRT
SIGKILL
无法处理和忽略。中止某个进程
SIGLWP
由Solaris Thread Libray内部使用
SIGPIPE
在reader中止之后写Pipe的时候发送
SIGPOLL
当某个事件发送给Pollable Device的时候发送
SIGPROF
Setitimer指定的Profiling Interval Timer所产生
SIGPWR
和系统相关。和UPS相关。
SIGQUIT
输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程
SIGSEGV
非法内存访问
SIGSTKFLT
Linux专用,数学协处理器的栈异常
SIGSTOP
中止进程。无法处理和忽略。
SIGSYS
非法系统调用
SIGTERM
请求中止进程,kill命令缺省发送
SIGTHAW
Solaris专用,从Suspend恢复时候发送
SIGTRAP
实现相关的硬件异常。一般是调试异常
SIGTSTP
Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程
SIGTTIN
当Background Group的进程尝试读取Terminal的时候发送
SIGTTOU
当Background Group的进程尝试写Terminal的时候发送
SIGURG
当out-of-band data接收的时候可能发送
SIGUSR1
用户自定义signal 1
SIGUSR2
用户自定义signal 2
SIGVTALRM
setitimer函数设置的Virtual Interval Timer超时的时候
SIGWAITING
Solaris Thread Library内部实现专用
SIGWINCH
当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程
SIGXCPU
当CPU时间限制超时的时候
SIGXFSZ
进程超过文件大小限制
SIGXRES
Solaris专用,进程超过资源限制的时候发送

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值