linux信号==Linux应用编程5

一、什么是信号

1、信号是内容受限的一种异步通信机制

  • (1)目的:用来通信
  • (2)本质: int型数字编号(事先定义好的)。
  • (3)特点:信号是异步的。

2、信号由谁发出

  • (1)用户中终端按下按键(如 Ctrl + C)。
  • (2)用户使用 kill 命令向其他进程发出信号。
  • (3)硬件异常后由操作系统发出信号。
  • (4)某种软件条件满足后也会发出信号,如 alarm 闹钟时间到会产生 SIGALARM 信号、向 一个读端已经关闭的管道 write 时会产生 SIGPIPE 信号。

3、信号由谁处理、如何处理

  • (1)信号由进程处理。
  • (2)信号处理方式:
    • ①忽略信号。
    • ②捕获信号(信号绑定了一个函数)。
    • ③默认处理:当前进程没有明显地理会这个信号,默认忽略或终止进程。
二、常见信号介绍
    1. SIGINT 2 Ctrl + C 时 OS 发送给前台进程中每个进程
    1. SIGABRT 6 调用 abort 函数,进程异常终止
    1. SIGPOLL SIGIO 8 指示一个异步 IO 事件,在高级 IO 中提及
    1. SIGKILL 9 杀死进程的终极办法
    1. SIGSEGV 11 无效存储访问时 OS 发出该信号
    1. SIGALARM 14 涉及 alarm 函数的实现
    1. SIGPIPE 13 涉及管道和 socket
    1. SIGTERM 15 kill 命令发送的默认终止信号
    1. SIGCHLD 17 子进程终止或停止时 OS 向其父进程发出此信号
    1. SIGUSR1 10 用户自定义信号,作用和意义由应用自己定义
    1. SIGUSR2 12 用户自定义信号,作用和意义由应用自己定义
三、进程对信号的处理

1、signal 函数介绍

  • (1)原型:sighandler_t signal(int signum,sighandler_t handler),
    同时需要配合捕获函数
    typedef void (*sighandler_t)(int)
  • (2)作用:用来对某一特定信号绑定一个捕获函数,signum是信号编号;handler是捕获函数指针(函数名),handler也可以设置为SIG_IGN(忽略)或SIG_DFL(默认);函数返回值是上一次对该信号设置的处理方式(出错时则返回SIG_ERR信号。)信号发生时该函数将signum传递给捕获函数。
  • (3)缺点:
    • 只能处理出现一次的信号,若信号出现第二次则恢复为默认处理
    • 要获取上一次对该信号的处理方式必须新建一个处理方式.

2、用 siganl 函数处理 SIGINT 信号

  • (1)默认处理。
  • (2)忽略处理。
  • (3)捕获处理。==搭配一个捕获函数
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
typedef void (*sighandler_t)(int);//宏函数指针
void func(int sig)//信号捕获函数
{
	if(SIGINT!=sig){
		return;printf("func for signal:%d.\n",sig);	
	}
}
int main(void)
{
	sighandler_t ret=(sighandler_t)-2;
	//===选择信号处理的方式
	//ret=signal(SIGINT,SIG_DFL);//指定信号SIGINT为默认处理方式
    //ret=signal(SIGINT,SIG_IGN);//指定信号SIGINT为忽略处理
    ret=signal(SIGINT,func);
    if (SIG_ERR == ret) {
 		perror("signal error"); exit(-1); 
     } 
	printf("before while(1)\n");
	while(1);
	printf("after while(1)\n");
	return 0;
}

3、sigaction 函数介绍

  • 原型 int sigaction(int signum,const struct sigaction* act,struct sigaction* oldact);
  • 两个均是API,但:
    • (1)sigaction比signal更具有移植性,因为signal在不同的内核版本中作用可能会不同
    • (2)sigaction 可处理多次出现的信号。
    • (3)sigaction可以通过两个struct sigaction指针不设置新处理方式而单独获取旧处理方式
#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h>  
static void sig_handler(int sig) 
{ 
     printf("Received signal: %d\n", sig); 
} 
int main(int argc, char *argv[]) 
{ 
     struct sigaction sig = {0}; 
     int ret;
     sig.sa_handler = sig_handler; 
     sig.sa_flags = 0; 
     ret = sigaction(SIGINT, &sig, NULL); 
     if (-1 == ret) { 
         perror("sigaction error"); 
         exit(-1); 
     }
     /* 死循环  */ 
     for ( ; ; ) { } 
     exit(0); 
}
四、alarm 函数和 pause 函数

1.alarm 函数

  • 内核以API形式提供闹钟:
    unsigned int alarm(unsigned int seconds)
    • seconds是闹钟的时间(秒);
    • 返回值是上个闹钟所剩余的时间,若之前没设置则为0.
    • 一个进程只允许设置一个闹钟,新的闹钟会替代旧的闹钟。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void func(int sig)
{
	if(sig==SIGALRM)
		printf("alarm happened.\n");
}
int main(void)
{
	unsigned int ret=-1;
	struct sigaction act={0};
	act.sa_handler=func;
	sigaction(SIGALRM,&act,NULL);
	//signal(SIGALRM,func);
	ret=alarm(5);printf("ret=%d.\n",ret);
	while(1);return 0;
}

2.pause 函数

  • 内核挂起: int pause(void)
    • 返回值始终为-1;
    • 要退出pause状态需要被信号唤醒。

3.使用 alarm 和 pause 来模拟 sleep

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void func(int sig)
{
	 printf("Received signal: %d\n", sig); 
}
void mysleep(unsigned int seconds);
int main(void)
{
	printf("before mysleep.\n");
	mysleep(3);
	printf("after mysleep.\n");
	return 0;
}
void mysleep(unsigned int seconds)
{
	struct sigaction act={0};
	act.sa_handler=func;//绑定信号捕获函数
	sigaction(SIGALRM,&act,NULL);
	alarm(seconds);
	pause();
}

若要详细了解linux信号,看我另一篇博客linux信号详解

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋哥爱做饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值