Linux信号机制

本文介绍了如何使用signal和sigaction函数来处理操作系统发出的信号,包括SIGALRM、SIGINT和SIGCHLD等,并展示了如何利用这些信号来管理进程的行为,如定时提醒和清理僵尸进程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       信号是在特定事件发生时由操作系统向进程发送消息。为了响应消息,执行与消息相关的自定义操作时的过程称为“信号处理”。

信号与signal函数
信号注册函数

#include<signal.h>
void(*signal(int signo,void (*func)(int)))(int);

函数名:signal
参数:int signo,void (*func)(int)
返回类型:参数为int型,返回void型函数指针
第一个参数为特殊情况信息,第二个参数为特殊情况下将要调用的函数的地址值。发生第一个参数代表的情况时,调用第二个参数所指的函数。

 

下面是可以在signal函数中注册的部分特殊情况和对应的常数:

SIGALRM:已到通过调用alarm函数注册的时间

SIGINT:输入CTRL+C
SIGCHLD:子进程终止
下面是信号注册过程:

signal(SIGCHLD,mychild);//子进程终止则调用mychild函数
signal(SIGALRM,timeout);//已到通过alarm函数注册时间,调用timeout函数
signal(SIGINT,keycontrol);//输入CTRL+C时调用keycontrol函数

下面是alarm函数:

#include<unistd.h>
unsigned int alarm(unsigned int seconds);
//返回0或以秒为单位的距SIGALRM信号发生所剩时间

下面是一个示例:

#include<sdtio.h>
#include<unistd.h>
#include<signal.h>

void timeout(int sig)
{
   if(sig==SIGALRM)
      puts("Time out!");
   alarm(2);
}
void keycontrol(int sig)
{
   if(sig==SIGINT)
      puts("CTRL+C pressed");
}

int main()
{
   int i;
   signal(SIGALRM,timeout);
   signal(SIGINT,keycontrol);
   alarm(2);

   for(i=0;i<3;i++)
   {
      puts("wait...");
      sleep(100);
   }
   return 0;   
}

       发生信号时将唤醒由于sleep函数而进入阻塞状态的进程。调用函数的主体是操作系统,但进程处于睡眠状态时无法调用函数。因此,产生信号时,为了调用信号处理器,将唤醒由于调用sleep函数而进入阻塞状态的进程。

利用sigaction函数进行信号处理
sigaction函数类似于signal函数,而且更稳定。

#include<signal.h>
int sigaction(int signo,const struct sigaction *act,struct sigaction *oldact);
---成功时返回0,失败时返回-1

signo---与signal函数相同,传递信号信息
act----对应于第一个参数的信号处理函数信息
oldact---通过此参数获取之前注册的信号处理函数指针,若不需要则传递0
声明并初始化sigaction结构体变量以调用上述函数,该结构体定义如下:

struct sigaction
{
   void (*sa_handler)(int);
   sigset_t sa_mask;
   int sa_flags;
}

       此结构体的sa_handler成员保存信号处理函数的指针值。sa_mask和sa_flags的所有位均初始化为0即可。这两个成员用于指定信号相关的选项和特性。
下面给出示例:

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

void timeout(int sig)
{
   if(sig==SIGALRM)
      puts("Time out!");
   alarm(2);
}

int main()
{
   int i;
   struct sigaction act;
   act.sa_handler=timeout;
   sigemptyset(&act.sa_mask); //sigemptyset函数将sa_mask成员的所有位初始化为0
   act.sa_flags=0;
   sigaction(SIGALRM,&act,0);
   alarm(2);
   for(i=0;i<3;i++)
   {
      puts("wait...");
      sleep(100);
   }
   return 0;
}

利用信号消灭僵尸进程

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>

void read_childproc(int sig)
{
   int status;
   pid_t id=waitpid(-1,&status,WNOHANG);
   if(WIFEXITED(status))
   {
      printf("Removed proc id:%d \n",id);
      printf("Child send:%d \n",WEXITSTATUS(status));
   }
}

int main()
{
   pid_t pid;
   struct sigaction act;
   act.sa_handler=read_childproc;
   sigemptyset(&act.sa_mask);
   act.sa_flags=0;
   sigaction(SIGCHLD,&act,0);
   
   pid=fork();
   if(pid==0){
      puts("Hi!I am child process");
      sleep(10);
      return 12;
   }
   else{
      printf("Child proc id:%d \n",pid);
      pid=fork();
      if(pid==0){
         puts("Hi!I am child process");
         sleep(10);
         exit(24);
      }
      else{
         int i;
         printf("child proc id:%d \n",pid);
         for(i=0;i<5;i++){
            puts("wait...");
            sleep(5);
         }
      }
   }
   return 0;  
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值