信号学习第一课--基础知识

信号是某些错误条件而引起由shell和终端管理器生成的
signal可以作为进程间传递消息或者修改行为的一种方式,明确的由一个进程传递给另外一个进程
信号可以被生成,捕获,响应,或者忽略。

程序可以使用signal库函数来处理信号

1 #include <signal.h>
2 void (* signal (int sig, void (* func) (int))) (int);

signal是一个带有sig和func两个参数的函数
  准备捕获或者忽略的信号由参数sig给出
  接收到指定的信号后将要调用的函数由参数func给出
  信号处理函数必须有一个int类型的参数也就是接收信号代码
  并且返回值是void
signal函数本身也返回一个同类型的函数,也就是先前用来处理这个信号的函数
处理信号的函数可以用下面的两个值代替:
  SIG_IGN忽略信号
  SIG_DFL恢复默认行为
信号处理实验程序:

 1 #include <signal.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4
 5 void ouch(int sig)//定义ouch函数,截获信号时候处理这个信号
 6 {
 7     printf("OUCH! - I got signal %d\n", sig);//先打印一句话
 8     (void) signal(SIGINT, SIG_DFL);//然后把一般由ctrl+c产生的SIGINT信号的处理方式恢复为默认形式
 9 }
10
11 int main()
12 {
13     (void) signal(SIGINT, ouch);//信号处理函数,第一个参数是准备捕获的或者忽略的信号,第二个参数是处理函数
14                 //在这里是指终端中断信号,有信号的时候截获,没信号的时候一直执行打招呼
15     while(1) {
16         printf("Hello World!\n");//一秒中循环打印一句招呼
17         sleep(1);
18     }//当再次按下终端中断信号时候,就会起终止程序的作用。
19 }

执行效果:

 1 [email protected]:~/c_program/544977-blp3e/chapter11$ ./ctrlc1
 2 Hello World!
 3 Hello World!
 4 Hello World!
 5 ^COUCH! - I got signal 2
 6 Hello World!
 7 Hello World!
 8 ^C
 9 [email protected]:~/c_program/544977-blp3e/chapter11$
10 //程序中信号SIGINT的值恰好是2

这是一种旧的信号处理函数,signal函数返回的是先前对指定信号进行处理的信号处理函数的指针
如果未定义信号处理函数,则返回SIG_ERR并设置errno为一个正值
如果给出的是一个无效的信号,或者尝试处理的信号是不可捕获的或者不可忽略的信号
例如SIGKILL信号,errno将被设置为EINVAL

发送信号

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

这个函数把参数sig给定的信号发送给参数pid给出的进城好所指定的进程,成功时返回0
要想发送一个信号,发送进程必须拥有相应的权限。
这通常意味这两个进程拥有相同的用户ID
也就是说用户只能发送信号给属于自己的进程,而超级用户可以给任何进程发送信号
失败的时候返回-1并设置errno变量

errno设置为EINVAL是因为给定的信号无效
errno设置为EPERM是因为发送进程权限不够
errno设置为ESRCH是因为目标进程不存在

闹钟函数:

1 #inlcude <unistd.h>
2 unsigned int alarm(unsigned int seconds);

调用这个函数的作用是在seconds秒之后安排发送一个SIGALRM信号
由于处理的延时和时间调度的不确定性,实际闹钟时间将比先安排的要稍微晚一点
参数seconds设置为0将取消所有的已设置的闹钟请求
要是在接收SIGALRM之后再次调用alarm函数则闹钟重新开始计时
每个进程只能有一个闹钟时间,alarm函数的返回值是以前设置的闹钟时间的剩余的秒数
失败的话返回-1

闹钟实验的程序:

 1 #include <signal.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4
 5 static int alarm_fired = 0;
 6
 7 void ding(int sig)
 8 {
 9     alarm_fired = 1;//设置一个整型为1
10 }
11
12 int main()
13 {
14     int pid;
15     printf("alarm application starting\n");
16     if((pid = fork()) == 0)
17     {
18         sleep(5);//在子进程中等待5秒
19         kill(getppid(), SIGALRM);//向父进程发送一个闹钟信号
20         exit(0);
21     }
22
23     printf("waiting for alarm to go off\n");
24     (void) signal(SIGALRM, ding);//安排信号处理,捕获闹钟信号到ding函数中
25
26     pause();//函数暂停运行,直到信号产生,程序继续运行
27     if (alarm_fired)
28         printf("Ding!\n");
29
30     printf("done\n");
31     exit(0);
32 }

程序的执行效果:

1 [email protected]:~/c_program/544977-blp3e/chapter11$ ./alarm
2 alarm application starting
3 waiting for alarm to go off
4 Ding!
5 done
6 [email protected]:~/c_program/544977-blp3e/chapter11$ 

健壮的信号接口

1 #include <signal.h>
2 int sigaction(int sig, const struct sigaction * act, struct sigaction * oact);

这个函数成功返回0失败的时候返回-1    
    第一个参数    sig要接收的信号
    第二个参数是一个结构指针
      sigaction这个结构是定义在接收到参数sig指定的信号后应该采取的行动
      这个结构至少拥有下面的三个成员:
        void (*) (int) sa_handler//是一个函数指针指向接收信号时将被调用的信号处理函数
        sigset_t sa_mask//指定了一个信号集,在调用信号处理函数之前,该信号集将被加入到信号屏蔽字中
        int sa_flags
    第三个参数是结构指针
    要是这个指针是空指针,sigaction将把原先对该信号的动作写到指向的位置
如果给出的信号或者试图对一个不允许捕获或者忽略的信号进行捕获或者忽略
错误变量errno将被设置为EINVAL

用这个函数代替信号处理函数signal的程序:

 1 #include <signal.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4
 5 void ouch(int sig)
 6 {
 7     printf("OUCH! - I got signal %d\n", sig);
 8 }
 9
10 int main()
11 {
12     struct sigaction act;
13
14     act.sa_handler = ouch;
15     sigemptyset(&act.sa_mask);
16     act.sa_flags = 0;
17
18     sigaction(SIGINT, &act, 0);//信号处理函数,遇到这个信号去指定的函数中区处理
19         //这个函数可以连续处理SIGINT信号
20   while(1) {
21     printf("Hello World!\n");
22     sleep(1);//没遇到之前一秒钟打一次招呼
23   }
24 }//终止程序需要提供SIGQUIT信号。由ctrl+\提供

程序执行的效果:

 1 [email protected]:~/c_program/544977-blp3e/chapter11$ ./ctrlc2
 2 Hello World!
 3 Hello World!
 4 ^COUCH! - I got signal 2
 5 Hello World!
 6 Hello World!
 7 Hello World!
 8 ^COUCH! - I got signal 2
 9 Hello World!
10 Hello World!
11 Hello World!
12 ^\退出 (核心已转储)
13 [email protected]:~/c_program/544977-blp3e/chapter11$

信号集

头文件signal.h定义了类型sigset_t和用来处理信号集的函数
sigaction和其他函数将用这些信号集来修改进程在接收到信号时的行为

1 #include <signal.h>
2 int sigaddset(sigset_t * set, int signo);//从信号集中增加给定的信号
3 int sigemptyset(sigset_t *set);//将信号集初始化为空
4 int sigfillset(sigset_t * set);//将信号集初始化为包含所有已知的信号
5 int sigdelset(sigset_t * set, int signo);//从信号集中减少给定的信号
6 //成功时返回0失败时返回-1并设置errno(当给定的信号无效时,设置为EINVAL)
1 #include <signal.h>
2 int sigismember(sigset_t * set, int signo);//函数的作用是检测给定的信号时候是一个信号集的成员
3 //如果是就返回1如果不是就返回0
4 //给定的信号无效就返回-1并设置errno为EINVAL
#include <signal.h>
int sigprocmask(int how, const sigset_t * set, signal_t * oset);
/*信号屏蔽字的设置和检查是由这个函数完成的
信号屏蔽字是指当前被阻塞的一组信号,它们不能被当前进程接收到
这个函数按照how提供的方法,设置新的信号屏蔽字
新的信号屏蔽字由set指定
旧的信号屏蔽字保存到信号集oset中
    how的取值和意义:
    SIG_BLOCK//把参数set中的信号添加到信号屏蔽字中
    SIG_SETMASK//把信号屏蔽字设置为参数set中的信号
    SIG_UNBLOCK//从信号屏蔽字中删除参数set中的信号
要是set是空指针的话how就没意义函数调用的目的就是将当前的信号屏蔽字的值保存在oset中
函数成功的话返回0要是how是无效的就返回-1并设置errno为EINVAL*/
1 #include <signal.h>
2 int sigpending(sigset_t * set);//函数的作用是把阻塞的信号中停留在待处理状态的一组信号写到参数set指向的信号集中
3 //成功的时候返回0失败的时候返回-1
1 #include <signal.h>
2 int sigsuspend(const sigset_t * sigmask);//函数将进程的信号屏蔽字替换为由参数sigmask给出的信号集
3 //然后挂起程序的执行,程序将在信号处理函数执行完毕之后继续执行,
4 //要是接收到的信号中止了程序那么这个函数不会返回
5 //要是接收到的信号没有中止程序那么这个函数就会返回-1并将errno设置为EINTR

参考文献:Linux程序设计 Neil Matthew

时间:2015年 06月 29日 星期一 17:09:28 CST

时间: 2024-08-30 12:26:05

信号学习第一课--基础知识的相关文章

HTML第一课——基础知识普及【2】

关注公众号:自动化测试实战 img标签 我们先看一下文档结构: 这里我们文件当前位置就是lesson.html,所以现在我们img属性src给的值要进入imgs文件夹,所以我们可以用相对路径来表示,看代码: <!DOCTYPE html><html>    <head>        <title>第一节课</title>        <meta charset="UTF-8"/>    </head>

(一)Python 学习第一天--基础知识,列表

1. .pyc文件 .pyc文件:在python3中,当模块运行时会自动生成在_pycache_文件夹中,其中c为compiled的缩写. Python是一门现编译后解释的语言,在运行时首先寻找.pyc文件,若没有先到内存先编译再解释,生成.pyc文件.如果源文件发生改动,则先对比对应的.pyc文件与源文件的时间戳. 2.数据类型 在Python2中当值大于2^64位时,为long型:Python3不存在long型,所有都为int型. 3.三元运算符 result = 值1  if   条件  

BurpSuite学习第一节--基础知识

一.BurpSuite的用处 Burp Suite是进行Web应用安全测试集成平台.在安全人员常用工具表(https://sectools.org/),burp suite排在第十三位 二.功能模块 Burp suite的模块几乎包含整个安全测试过程,从最初对目标程序的信息采集,到漏洞扫描及其利用 主要模块: Target(目标)--- Proxy(代理)---是一个拦截HTTP/S的代理服务器,作为一个在浏览器和目标应用程序之间的中间人.允许拦截,查看,修改在两个方向上的原始数据流 Spide

Magento学习第一课——目录结构介绍

Magento学习第一课--目录结构介绍 一.Magento为何强大 Magento是在Zend框架基础上建立起来的,这点保证了代码的安全性及稳定性.选择Zend的原因有很多,但是最基本的是因为zend框架提供了面向对象的代码库并且有很好的团队支持.通过这个框架,Magento主要围绕三个基本点建立: 1. 灵活性:我们相信每一个解决方案都像它的商务支持一样是独一无二的.Magento的代码可以无缝定制的. 2. 可升级性:Magento可方便的实行定制且不丧失升级的能力,因为从社区中获得核心代

如何学习FPGA?FPGA学习必备的基础知识

如何学习FPGA?FPGA学习必备的基础知识 时间:2013-08-12 来源:eepw 作者: 关键字:FPGA   基础知识 FPGA已成为现今的技术热点之一,无论学生还是工程师都希望跨进FPGA的大门.网络上各种开发板.培训班更是多如牛毛,仿佛在告诉你不懂FPGA你就OUT啦.那么我们要玩转FPGA必须具备哪些基础知识呢?下面我们慢慢道来. (一) 要了解什么是FPGA 既然要玩转FPGA,那我们首先最重要的当然是要了解什么FPGA.FPGA(Field-Programmable Gate

Scala学习:第一张基础 - 心得

这是一个神奇的语言. 安装环境就够折腾了,居然还挑eclipse,最新的4.4居然不支持,要用4.3.2 第一张都是些简单的概念介绍,但是通过第一张可以看出scala和其他语言的语法上存在较大的区别(当然根据我的知识范围也就是指的c#,Java) 关键点: 1.Scala中,我们不需要包装类型. 读到这里时,我对性能产生了担心,于是赶快查了下对Scala和Java的性能对比.有个比较好的文章.内容不多,字字珠玑. 不要使用for循环 不要使用scala.collection.mutable 不要

《汇编语言》学习笔记1——基础知识

第一章   基础知识 汇编语言的组成 汇编指令:机器码的助记符,有对应的机器码(汇编语言的核心) 伪指令:没有对应的机器码,由编译器执行,计算机并不执行 其他符号:如:+.-.*./等,由编译器识别,没有对应的机器码 指令和数据都是应用上的概念,在内存或磁盘上指令和数据都是二进制信息. 存储器被划分为若干个存储单元,每个存储单元从0开始. 一个存储器有128个存储单元,一个存储单元存储一个字节,一个字节有8个二进制位. 内存换算: 1bit=8byte(B).1KB=1024B.1MB=1024

Kubernetes 第一章 基础知识

Kubernetes 第一章 基础知识 Kubernetes是一个开源容器编排引擎,用于自动化容器化应用程序的部署,扩展和管理.开源项目由Cloud Native Computing Foundation(CNCF)托管. Kubernetes是一个可移植,可扩展的开源平台,用于管理容器化工作负载和服务,有助于声明性配置和自动化.它拥有庞大,快速发展的生态系统.Kubernetes服务,具有广泛的工具和支持可用. 发展历程 传统部署时代: 早期,组织在物理服务器上运行应用程序.无法为物理服务器中

wpf(第一章 基础知识)

wpf第一章基础知识:通过vs2015创建wpf程序会在引用里面多出3个核心程序集PresentationCore.PresentationFramework.WindowsBase.并且会在解决方案中生成如下的结构: 1.程序起始相关的资源:2.与整个wpf相关的后台代码:3.窗体界面:4.窗体界面的后台代码. 在app.xaml中 1.Application的后台类:2.启动窗体:3.系统资源区域 除此之外可以在MainWindow.xaml中自定义窗体设置属性,拖拉控件在里面.