信号实现进程间的通信
3.5.1.什么是信号
3.5.1.1、信号是内容受限(只是一个int型的数字)的一种异步通信机制
(1)信号的目的:用来通信(进程与进程之间的通信)
(2)信号是异步的(对比硬件中断),信号好像就是一种软件中断。
(3)信号本质上是int型数字编号(事先定义好的)
3.5.1.2、信号由谁发出
(1)用户在终端按下按键
(2)硬件异常后由操作系统内核发出信号
(3)用户使用kill命令向其他进程发出信号
(4)某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时会产生SIGPIPE信号
3.5.1.3、信号由谁处理、如何处理
(1)忽略信号
(2)捕获信号(信号绑定了一个函数)
(3)默认处理(当前进程没有明显的管这个信号,默认:忽略或终止进程)
 
 
3.5.2.常见信号介绍(信号的名字 )
    信号宏                    num                                         信号对应的作用
(1)【SIGINT    】                2                                             Ctrl+C时OS送给【前台】进程组中【每个】进程
(2)SIGABRT                        6                                            调用abort函数,进程异常终止
(3)【SIGPOLL    /   SIGIO    】        8                                   指示一个异步IO事件,在高级IO中提及
(4)【SIGKILL】                            9                                杀死进程的终极办法
(5)SIGSEGV                       11                                            无效存储访问时OS发出该信号
(6)【SIGPIPE    】                   13                                    涉及(异步通信的)管道和socket
(7)【SIGALARM】                       14                                涉及alarm函数的实现
(8)SIGTERM                       15                                             kill命令发送的OS默认终止信号
(9)【SIGCHLD    】               17                                         子进程终止或停止时OS向其父进程发此信号等待父进程回收
以上所有信号的作用都是事先定义好的。
(10)
SIGUSR1                           10                                          用户自定义信号,作用和意义由应用自己定义
SIGUSR2                           12
这两个名称是预先已经定义好了的,但是作用是用户自己定义的。
 
3.5.3.进程对信号的处理
3.5.3.1、signal函数介绍
signal()函数理解
在<signal.h> 这个头文件中。
signal(参数1,参数2);
参数1:我们要进行处理的信号。系统的信号我们可以再终端键入 kill -l查看(共64个)。其实这些信号就是系统定义的宏。
root@ubuntu:/mnt/hgfs/Winshare/1.Linux应用编程和网络编程/7.thread# kill -l
 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX   
参数2:我们处理这些信号的方式(是系统默认还是忽略还是捕获)。
一般有3中方式进行操作。
1)eg: signal(SIGINT ,SIG_IGN );          //忽略处理
//SIG_ING 代表忽略SIGINT信号,SIGINT信号代表由InterruptKey产生,通常是CTRL +C 或者是DELETE 。发送给所有ForeGround Group的进程。
2)eg: signal(SIGINT ,SIG_DFL );      //默认处理(当前进程没有明显的管这个信号,默认:忽略或终止进程)
//SIGINT信号代表由InterruptKey产生,通常是CTRL +C或者是DELETE。发送给所有ForeGroundGroup的进程。 SIG_DFL代表执行系统默认操作,其实对于大多数信号的系统默认动作时终止该进程。这与不写此处理函数是一样的。
3)捕获信号并处理(信号绑定了一个函数)
3.5.3.2、用signal函数处理SIGINT信号
(1)忽略处理
#include<stdio.h>
#include<signal.h>
int main(void)
{
    signal(SIGINT ,SIG_IGN ); 
    while(1)
    {
        printf("hello world!\n");
        sleep(1);
    }
    return 0;
}
(2)默认处理
signal(SIGINT ,SIG_DFL )
#include<stdio.h>
#include<signal.h>
int main(void)
{
signal(SIGINT ,SIG_DFL );
    while(1)
    {
        printf("hello world!\n");
        sleep(1);
    }
    return 0;
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
(3)捕获处理
signal函数原型:
#include <signal.h>
typedef void (*sighandler_t)(int);    //typedef sighandler_t这个函数指针变量类型,重命名一种类型
sighandler_t signal(int signum, sighandler_t handler);//第二个参数是一个函数指针类型的变量,将来传进去一个函数名;返回一个函数指针。
 
细节:
(1)signal函数绑定一个捕获函数后信号发生后会自动执行绑定的捕获函数,并且把信号编号s数字作为传参传给捕获函数
(2)signal的返回值在出错时为SIG_ERR,绑定成功时返回指向我们自定义的捕获函数的函数指针。
(3)signal()函数(它自己是带两个参数,一个整型的信号编号,以及一个指向用户自定义的信号处理函数的指针。),而这个signal()函数的返回值也为一个函数指针,【这个函数指针指向一个带一个整型参数,并且返回值为void的一个函数.】(也就是说signal()函数的返回值和我们向它里面传递的第二个参数的类型是一样的,都是一个函数指针类型的,且这个函数指针指向的函数的返回值为void,参数为int)【相当于我们在signal函数的两个接收参数中第二个参数是向系统中【绑定】这个要执行的函数】,等到我们第一个参数中注册的信号真的发生了之后,我们signal函数的返回值就指向了我们用户自定义的函数去执行它。
(4)signal函数的返回值,它的返回值为一个函数指针,如果signal函数执行错误,则返回SIG_ERR,如果执行成功则返回一个指向自定义函数的函数指针。
(5)等于说我们在第二个参数中是向内核注册(绑定)我们的自定义函数,而当信号真的发生后,返回一个指向我们自定义函数的函数指针,是去执行我们的绑定的自定义函数。
 
代码示例:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
typedef void (*sighandler_t)(int);            //重新声明一个函数指针sighandler_t
void func(int sig)
{
    if (SIGINT == sig)
 
    printf("func for signal: %d.\n", sig);
    exit(-1) ;
}
int main(void)
{
    sighandler_t ret ; //ret为一个函数指针变量,指向一个函数
    ret=signal(SIGINT, func);          //相当于先向系统中注册这个函数,SIGINT是Ctrl+C时OS送给【前台】进程组中【每个】进程
     //signal(SIGINT, SIG_DFL);        // 指定信号SIGINT为默认处理
    //ret = signal(SIGINT, SIG_IGN);        // 指定信号SIGINT为忽略处理
    if (SIG_ERR == ret)
    {
        perror("signal:");
        exit(-1);
    }
    printf("before loop\n");
    while(1)
    {
        printf("hello world!\n");
        sleep(1);
    }
    printf("after loop\n");
    return 0;
}
 
3.5.3.3、signal函数的优点和缺点
(1)优点:简单好用,捕获信号常用
(2)缺点:无法简单直接得知之前设置的对信号的处理方法
3.5.3.4、sigaction函数介绍
#include <signal.h>
int sigaction(int sig, const struct sigaction *act,struct sigaction *oact);
(1)2个都是API,但是sigaction比signal更具有可移植性
(2)用法关键是sigaction函数的两个指针参数
 
sigaction比signal好的一点:sigaction可以一次得到设置新捕获函数和获取旧的捕获函数(其实还可以单独设置新的捕获或者单独只获取旧的捕获函数),而signal函数不能单独获取旧的捕获函数而必须在设置新的捕获函数的同时才获取旧的捕获函数。
sigaction代码示例:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void func(int sig)
{
    if(SIGINT!=sig)
        return ;
    printf("信号num是:%d\n",sig);
}
int main(void)
{
    struct sigaction act;
    act.sa_handler=func;
    int res=-1;
    res=sigaction(SIGINT,&act,NULL);
    if(res==-1)
    {
        perror("sigaction");
        _exit(-1);
    }
 
    printf("before loop:\n");
    while(1)
    {
        printf("hello world\n");
        sleep(1);
    }
return 0;
}
 
3.5.4.alarm和pause函数
3.5.4.1、alarm函数:主要是在设定秒数后向signal发送信号,然后执行绑定函数;alarm()函数用于在系统中设置一个定时器,在定时器到时后会向进程发送SIGALRM信号。SIGALRM信号的 默认处理方式是终止进程。
(1)内核以API形式提供的闹钟(内核帮一个进程只维护一个alarm时钟)
(2)编程实践
所需头文件
  #include<unistd.h>
函数原型
  unsigned int alarm(unsigned int seconds)
函数参数
  seconds:指定秒数
函数返回值
  成功:如果调用此alarm()前,进程已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
  出错:-1
 注意:alarm只设定一个闹钟,时间到达并执行其注册函数之后,闹钟便失效。【如果想循环设置闹钟,需在其注册函数(hander函数中)再调用alarm函数。】
 
 代码示例:
 #include<unistd.h>
#include<signal.h>
#include<stdio.h>
void handler()
{
    printf("Hello。。。。。\n");
  
}
 
void main()
{
    int i;
 
    signal(SIGALRM, handler); //让内核做好准备,一旦接受到SIGALARM信号,就执行 handler
    alarm(5);//在5秒过后执行handler函数
    for(i=1;i<21;i++)
    {
        printf("sleep %d ...\n",i);
        sleep(1);
    }
}
 
 
3.5.4.2、pause函数
(1)内核挂起
(2)代码实践
pause函数的作用就是让当前进程暂停运行,交出CPU给其他进程去执行。当当前进程进入pause状态后当前进程会表现为“卡住、阻塞住”,要退出pause状态当前进程需要被信号唤醒。
3.5.4.3、使用alarm和pause来模拟sleep
 
pause函数代码示例:
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
 
void sigroutine(int unused)
{
    printf("Catch a signal SIGINT \n");
}
 
int main()
{
        signal(SIGINT, sigroutine);//SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出
        pause();//在没有收到任何的信号的时候,pause相当于一个死循环,当收到任何一个信号的时候,就执行下一句
        sleep(3);
        printf("receive a signal \n");
}
 
 
使用alarm和pause来模拟sleep代码示例:
#include <stdio.h>
#include <unistd.h>            // unix standand
#include <signal.h>
void func(int sig)
{
    /*
    if (sig == SIGALRM)
    {
        printf("alarm happened.\n");
    }
    */
}
 
void mysleep(unsigned int seconds);
int main(void)
{
    printf("before mysleep.\n");
    mysleep(3);
    printf("after mysleep.\n");
/*    unsigned int ret = -1;
    struct sigaction act = {0};
 
    act.sa_handler = func;
    sigaction(SIGALRM, &act, NULL);
 
    //signal(SIGALRM, func);
    ret = alarm(5);
    printf("1st, ret = %d.\n", ret);
 
 
    sleep(3);
 
    ret = alarm(5);        // 返回值是2但是本次alarm会重新定5s
    printf("2st, ret = %d.\n", ret);
    sleep(1);
 
    ret = alarm(5);
    printf("3st, ret = %d.\n", ret);
 
 
 
 
    //while (1);
    pause();       
*/   
    return 0;
}
 
void mysleep(unsigned int seconds)
{
    struct sigaction act = {0};
 
    act.sa_handler = func;
    sigaction(SIGALRM, &act, NULL);
 
    alarm(seconds);
    pause();
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

(50)LINUX应用编程和网络编程之五 Linux信号(进程间通信)的更多相关文章

  1. (46)LINUX应用编程和网络编程之一Linux应用编程框架

    3.1.1.应用编程框架介绍 3.1.1.1.什么是应用编程 (1)整个嵌入式linux核心课程包括5个点,按照学习顺序依次是:裸机.C高级.uboot和系统移植.linux应用编程和网络编程.驱动. ...

  2. Linux下高并发网络编程

      Linux下高并发网络编程 1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时, 最高的并发数量都要受到系统对用户单一进程同时可打 ...

  3. 老师的blog整理 .网络编程部分 .网络编程部分 前端部分 django基础部分

    老师的blog整理 .网络编程部分 .网络编程部分 前端部分 django基础部分   老师的blog整理 python基础部分: 宝哥blog: https://www.cnblogs.com/gu ...

  4. linux服务器开发三(网络编程)

    网络基础 协议的概念 什么是协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则. 假设,A.B双方欲传输文件.规定: 第一次,传输文件名,接收方接收到文件名 ...

  5. Linux IO模型和网络编程模型

    术语概念描述: IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者. 阻塞和非阻塞,是函数/方法的实现方式,即在数据就绪之前是立刻返回还是等待. 以文件IO为例,一个IO读过程是文件 ...

  6. linux服务端的网络编程

    常见的Linux服务端的开发模型有多进程.多线程和IO复用,即select.poll和epoll三种方式,其中现在广泛使用的IO模型主要epoll,关于该模型的性能相较于select和poll要好不少 ...

  7. UNIX网络编程——揭开网络编程常见API的面纱【下】

    Linux网络编程数据收发的API流程分析        只要把数据在协议栈中的流动线路和脉络弄清楚了,关于协议栈的实现部分,理解起来就轻松多了.在网络编程章节的数据接收过程中,我们主要介绍过read ...

  8. UNIX网络编程——揭开网络编程常见API的面纱【上】

    Linux网络编程API函数初步剖析 今天我们来分析一下前几篇博文中提到的网络编程中几个核心的API,探究一下当我们调用每个API时,内核中具体做了哪些准备和初始化工作. 1.socket(famil ...

  9. TCP/IP网络编程之网络编程和套接字

    网络编程和套接字 网络编程又称为套接字编程,就是编写一段程序,使得两台连网的计算机彼此之间可以交换数据.那么,这两台计算机用什么传输数据呢?首先,需要物理连接,将一台台独立的计算机通过物理线路连接在一 ...

随机推荐

  1. OpenTSDB查询和写入毫秒级数据

    由于OpenTSDB没有支持Java的SDK进行调用,所以基于Java开发OpenTSDB的调用将要依靠HTTP请求的方式进行. 1.毫秒级数据写入 /api/put:通过POST方式插入JSON格式 ...

  2. C语言---进制

    1. 何为进制 进位机制,逢几进一.数值某一位置上的数在运算时是逢几进一. 生活中的进制:十进制.十二进制(12个月是1年).六十进制(60秒是1分钟) 计算机编程中的进制:二进制.八进制.十六进制. ...

  3. C++笔记(0)——判定一个数字是否是素数

    博主之前使用的编程语言是Python,但是这门语言的效率比较低(通常,不优化的情况下,但是即便如此我还是偏爱Python),而且博主打算参加PAT考试(真正的原因),及博主打算顺便深入学习下机器学习框 ...

  4. 普通交叉验证(OCV)和广义交叉验证(GCV)

    普通交叉验证OCV OCV是由Allen(1974)在回归背景下提出的,之后Wahba和Wold(1975)在讨论 了确定多项式回归中多项式次数的背景,在光滑样条背景下提出OCV. Craven和Wa ...

  5. info - 阅读 info 文档

    SYNOPSIS 总览 info [OPTION]... [MENU-ITEM...] DESCRIPTION 描述 阅读 info 格式的文档. OPTIONS 选项 --apropos=STRIN ...

  6. 学习-Pytest(三)setup/teardown

    1. 用例运行级别 模块级(setup_module/teardown_module)开始于模块始末,全局的 函数级(setup_function/teardown_function)只对函数用例生效 ...

  7. python-字符编码的转换

    python-字符编码的转换 1.了解基础知识 ASCII  一个英文,占一个字节.只能存英文和特殊字符. gb2312 约可以存7000中文 gb1830 约可以存27000中文 gbk 默认中文, ...

  8. vue修改富文本中的元素样式

    富文本编辑器目前应用很广泛,而有时候我们想要对其中的一些元素的样式进行修改,就会遇到问题. 首先,直接修改是不可行的,因为是用v-html标签进行渲染的,无法直接获取到. 在修改的时候,一般是按标签进 ...

  9. Directed Roads CodeForces - 711D (基环外向树 )

    ZS the Coder and Chris the Baboon has explored Udayland for quite some time. They realize that it co ...

  10. Codeforces 911 三循环数覆盖问题 逆序对数结论题 栈操作模拟

    A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...