07_Linux信号

1、信号的概述

信号是Linux进程间通信的最古老的方式。信号是软件中断,它是在 软件层次上对中断机 制的一种模拟,是一种异步通信的方式。 信号可以导致一个 正在运行的进程被另一个正在运行的异步进程中断,转而处理某一个突 发事件。

特点:简单不能携带大量信息满足某个特设条件才发。 一个完整的信号周期包括三个部分: 信号 的产生,信号在进程中的注册(执行信号处理函数),信号在进程中的注销。

查看信号编号:kill -l

其中1-31号信号称之为常规信号(也叫普通信号或标准 信号),34-64称之为实时信号, 驱动编程与硬件相关。

终端上按“Ctrl+c”组合键通常产生 中断信号SIGINT

终端上按“Ctrl+\”键通常产生中断信号SIGQUIT

终端上按 “Ctrl+z”键通常产生中断信号SIGSTOP等

2、信号产生

a) 当用户按某些终端键时,将产生信号。终端上按“Ctrl+c”组合键通常产生 中断信号 SIGINT 终端上按“Ctrl+\”键通常产生中断信号 SIGQUIT终端上按 “Ctrl+z”键通常产生中断信 号SIGSTOP等。

b) 硬件异常将产生信号。除数为 0,无效的内存访问等。这些情况通常由硬件检测到,并 通知内核,然后内核产生 适当的信号发送给相应的进程。

c) 软件异常将产生信号。当检测到某种软件条 件已发生(如:定时器alarm),并将其通知 有关进程时,产生信号。

d) 调用系统 函数(如:kill、raise、abort)将发送信号。 注意:接收信号进程和发送信号进 程 的所有者必须相同,或发送信号进程的所有者必须是超级用户。

e) 运行kill /killall 命令将发送信号。此程序实际上是使用kill函数来发送信号。也常用此命 令终止一个失控的后台进程。

3、未决信号集合、信号阻塞集

产生信号后,在未决信号集中查看未解决的信号,然后在信号阻塞集中查看该信号是否被阻塞,如果阻塞就一直循环这个过程,如果未阻塞就进行信号处理

4、API

kill()

kill(pid,9)

raise()

abort()

alarm()

返回上一个闹钟剩余的秒数

setitimer()   

通过signal改变SIGALRM信号的功能,默认是终止进程。

5、修改信号的处理方式

SIGKILL 和 SIGSTOP 不能更改信号的处理方式,因为它们向用户提供了一种使进程终止的可
靠方法。
信号处理方式 一个进程收到一个信号的时候,可以用如下方法进行处理:
1 )执行系统默认动作 对大多数信号来说,系统默认动作是用来终止该进程。
2 )忽略此信号 ( 丢弃 ) 接收到此信号后没有任何动作。
3 )执行自定义信号处理函数( 捕获 ) 用用户定义的信号处理函数处理该信号。
signa()
sigaction()
1)sa_handler、sa_sigaction:信号处理函数指针,和signal()里的函数指针用法一样,应根 据情况给sa_sigaction、sa_handler两者之一赋值,其取值如下:
      a) SIG_IGN:忽略该信号
      b)SIG_DFL:执行系统默认动作
      c)处理函数名:自定义信号处理函数
2)sa_mask:信号阻塞集,在信号处理函数执行过程中,临时屏蔽指定的信号。
3)sa_flags:用于指定信号处理的行为,通常设置为0,表使用默认属性。 它可以是以下值的“按位或”组合:
        SA_RESTART:使被信号打断的系统调用自动重新发起(已经废弃)                                              SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到SIGCHLD信号。
        SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到SIGCHLD信号,这时子进程 如果退出也不会成为僵尸进程。
       SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信 号。               SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
       SA_SIGINFO:使用sa_sigaction成员而不是sa_handler作为信号处理函数。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
char *p;
void my_deal_func(int sig)
{
    if (p != NULL)
    {
        free(p);
        p = NULL;
    }
    printf("我自己释放了p\n");
    //_exit(-1);
    return;
}
int main(int argc, char const *argv[])
{
    struct sigaction act;
    // 保存自定义函数的入口地址
    act.sa_handler = my_deal_func;

    // 将所有信号添加到集合中
    sigset_t set;
    sigfillset(&set);
    act.sa_mask = set;

    // 信号的处理方式
    //act.sa_flags = 0;
    act.sa_flags |= SA_RESETHAND;

    // 注册 CTRL+C信号的处理函数
    sigaction(SIGINT, &act, NULL);

    p = (char *)calloc(1, 128);
    strcpy(p, "hello signal");
    printf("p=%s\n", p);

    while (1)
        ;

    printf("p指向的堆区空间释放了\n");
    free(p);
    return 0;
}

自定义信号

6、集合

在PCB中有两个非常重要的信号集。一个称之为“阻塞信号集”,另一个称之为“未 决信号 集”。这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我 们直接对其进 行位操作。而需自定义另外一个集合,借助信号集操作函数来对PCB 中的这两个信号集进 行修改。

 
信号阻塞集
信号阻塞集也称信号屏蔽集、信号掩码。每个进程都有一个阻塞集,创建子进程时 子进程 将继承父进程的阻塞集。信号阻塞集用来描述哪些信号递送到该进程的时候 被阻塞(在信号发生时记住它,直到进程准备好时再将信号通知进程)。所谓阻 塞并不 是禁止传送信号,而是暂缓信号的传送。若将被阻塞的信号从信号阻塞集中 删除,且对应 的信号在被阻塞时发生了,进程将会收到相应的信号。
sigprocmask()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
char *p;
void my_deal_func(int sig)
{
    if (p != NULL)
    {
        free(p);
        p = NULL;
    }
    printf("我自己释放了p\n");
    _exit(-1);
    return;
}
int main(int argc, char const *argv[])
{
    // 注册 CTRL+C信号的处理函数
    signal(SIGINT, my_deal_func);

    // 将SIGINT添加到阻塞集
    sigset_t set;
    // 清空集合
    sigemptyset(&set);
    // 将SIGINT添加到信号集set中
    sigaddset(&set, SIGINT);

    // 将set信号集 添加到 阻塞集中
    sigprocmask(SIG_BLOCK, &set, NULL);
    printf("已经将SIGINT添加到阻塞集中,持续时间10秒\n");

    p = (char *)calloc(1, 128);
    strcpy(p, "hello signal");
    printf("p=%s\n", p);

    sleep(10);
    printf("已经将SIGINT从阻塞集删除\n");
    sigprocmask(SIG_UNBLOCK, &set, NULL);

    while (1)
        ;

    printf("p指向的堆区空间释放了\n");
    free(p);
    return 0;
}

7、进程间通信方式

1、管道(无名管道) 有血缘关系的进程、半双工、一对一、先进先出、无格式、数据读取一次性,在内存。
2、有名管道 无血缘关系的进程,半双工、一对一、先进先出、无格式、数据读取一次性,在内存。
3、消息队列 多对多、按消息类型收发、同类型数据先进先出、有格式、数据读取一次性,在内存。
4、磁盘映射(mmap) 多对多、无格式、数据读取非一次性,写入数据覆盖原来数据,在磁盘。 5、共享内存 多对多、无格式、数据读取非一次性,写入数据覆盖原来数据,读写速度最快,在内存 中。
6、信号 简单、不能携带大量数据、在特定的条件下触发。
7、套接字socket 不同主机的进程间通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值