20191320-2021-2022-1-diocs 学习笔记9

第6章 信号和信号处理

6.1~6.3 信号和中断

中断:中断是I/O设备发送到CPU的外部请求,将CPU从正常执行转移到中断处理。
信号:信号是发送给进程的请求,将进程从正常执行转移到中断处理。
中断的类型:

  1. 人员中断
  2. 进程中断
  3. 硬件中断
  4. 进程的陷阱错误

Unix/Linux支持31种不同的信号,每种信号在signal.h文件中都有定义。

#define  	SIGHUP  	1
#define  	SIGINT  	2
#define  	SIGQUIT  	3
#define  	SIGILL  	4
#define  	SIGTRAP  	5
#define  	SIGABRT  	6
#define  	SIGIOT  	6
#define  	SIGBUS  	7
#define  	SIGFPE  	8
#define  	SIGKILL  	9
#define  	SIGUSR1  	10
#define  	SIGSEGV  	11
#define  	SIGUSR2  	12
#define  	SIGPIPE  	13
#define  	SIGALRM  	14
#define  	SIGTERM	        15
#define  	SIGSTKFLT	16
#define  	SIGCHLD    	17
#define  	SIGCONT	        18
#define  	SIGSTOP      	19
#define  	SIGTSTP	        20
#dpfine  	STGTTTN	        21
#define  	SIGTTOU	        22
#define  	SIGURG	        23
#define  	SIGXCPU	        24
#define  	SIGXFSZ    	25
#define  	SIGVTALRM	26
#define  	SIGPROF  	27
#define  	SIGWINCH	28
#define  	SIGPOLL  	29
#define  	SIGPWR	        30
#define  	SIGSYS	        31

这些信号的不同来源有:

  • 来自硬件的中断信号
  • 来自异常的信号
  • 来自其他进程的信号

6.4~6.7 信号处理步骤、IPC

在许多操作系统的书籍中,信号被归类为进程间的通信机制。基本原理是一个进程可以向另一个进程发送信号,使它执行预先安装的信号处理函数。

  • 该机制并不可靠,因为可能会丢失信号。每个信号由位向量中的一个位表示,只能记 录一个信号的一次岀现.如果某个进程向另一个进程发送两个或多个相同的信号,它 们可能只在接收PROC中出现一次。实时信号被放入队列,并保证按接收顺序发送, 但操作系统内核可能不支持实时信号。
  • 竞态条件:在处理信号之前,进程通常会将信号处理函数重置为DEFault。要想捕捉同一信号的再次出现,进程必须在该信号再次到来之前重新安装捕捉函数。否则,下 一个信号可能会导致该进程终止。在执行信号捕捉函数时,虽然可以通过阻塞同一信 号来防止竞态条件,但是无法防止丢失信号。
  • 大多数信号都有预定义的含义。不加区别地任意使用信号不仅不能达到通信的目的,反而会造成混乱。例如,向循环进程发送SIGSEGV(11)段错误信号,出现错误的信息。
    因此,试图将信号用作进程间通信手段实际上是对信号预期用途的过度延伸.应避免出现这种情况。

实践内容过程、问题解决过程

按照书上的代码进行了实践,如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>
jmp_buf env;
int count = 0;
void handler(int sig, siginfo_t *siginfo, void *context)
{
    printf("handler: sig=%d from PID=%d UID=%d count=%d\n",
           sig, siginfo->si_pid, siginfo->si_uid, ++count);
    if (count >= 4) // let it occur up to 4 times
        longjmp(env, 1234);
}
int BAD()
{
    int *ip = 0;
    printf("in BAD(): try to dereference NULL pointer\n");
    *ip = 123; // dereference a NULL pointer
    printf("should not see this line\n");
}
int main(int argc, char *argv[])
{
    int r;
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction = &handler;
    act.sa_flags = SA_SIGINFO;
    sigaction(SIGSEGV, &act, NULL);
    if ((r = setjmp(env)) == 0)
        BAD();
    else
        printf("proc %d survived SEGMENTATION FAULT: r=%d\n", getpid(), r);

    printf("proc %d looping\n", getpid());
    while (1)
        ;
}

实践截图:

代码链接

代码包括一些以前的代码,在码云。链接:https://gitee.com/Ressurection20191320/code/tree/master/IS

posted @ 2021-11-13 16:52  20191320  阅读(31)  评论(0编辑  收藏  举报