进程-信号的基本概念和产生函数

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

        这里我们学习的信号就是属于这么一种中断。我们在终端上敲Ctrl + c就产生了一个中断,相当于产生了一个信号,接着就会处理这个一个中断任务

信号的特点:
1.简单
2.不能携带大量信息
3.满足某个特设条件才能发送

信号可以直接进行用户空间进程和内核空间进程的交互,内核进程可以利用它来通知用户空间进程发生了哪些系统事件。

一个完整的信号周期包括三个部分:信号的产生,信号在进程中的注册,信号在进程中的注销,执行信号处理函数

信号的编号 

unix早期版本就提供了信号机制,但不可靠,信号可能丢失,之后对信号模型做了更改,增加了可靠的信号机制,但彼此不兼容,POSIX.1对可靠信号例程进行了标准化

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

具体信号列表参考Linux信号列表_baobao8505的博客-CSDN博客_linux信号列表

信号的四要素

1.编号        2.名称        3.事件        4.默认处理动作

不同的操作系统下 编号是不同的 但是名称却都是相同的

Action为默认动作:

Term:终止进程
Ign:忽略进程
Core:终止进程,生成Core文件
Stop:停止进程
Cont:继续运行进程

注意:SIGKILL和SIGSTOP信号,不允许忽略和捕捉,只能执行默认动作。甚至不能将其设置为阻塞。

信号产生后有两个状态 
1.未决状态:没有被处理
2.递达状态:信号被处理了

阻塞信号集和未决信号集

 信号的实现手段导致信号有很强的延时性,但对于用户来说,时间非常短,不易察觉

阻塞信号集
        将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,再收到该信号,该信号的处理将推后(处理发生在解除屏蔽之后)

未决信号集
        信号产生,未决信号集中描述该信号的位立即翻转为1,表示该信号处于未决状态。当信号被处理对应位翻转回为0.这一时刻往往非常短暂。

信号产生函数 

kill函数

普通用户是不能向系统用户发送信号的,super用户可以发送信号给任意用户

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>

//parent process kill child process
int main(void){
    pid_t pid = -1; 
    
    pid = fork();
    if(-1 == pid){
        perror("fork");
        return 1;
    }   
    
    //child process
    if(0 == pid){
        while(1){
            printf("child process do work...\n");
            sleep(1);
        }

        //exit process
        exit(0);
    }   
    else
    {   
        //parent process

        sleep(3);
        printf("child process is time to exit...\n");
        kill(pid,15);   
        printf("parent process is time to over...\n");
    
    }   

    return 0;
}

这里我们用kill在sleep3秒后杀死了子进程 所以在执行3次do work输出后 就会终止

使用raise函数向自己发送信号

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

int main(void){
    int i= 1;
    while(1){
        printf("do working %d\n",i);
    
        if(i == 4){ 
            //send a id 15 signal to myself
            raise(SIGTERM);
        }
        i++;
        sleep(1);
    }   

    return 0;
}

输出结果: 

do working 1
do working 2
do working 3
do working 4
Terminated

这里我们用raise给自己发送了一个SIGTERM信号  如果是使用kill那么就是
kill(getpid(),SIGTERM); 这里的getpid()是获取当前进程id 

abort函数

默认是发送6号终止信号 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void){
    int i = 1;
    while(1){
        printf("do working %d\n",i);

        if(4 == i){ 
            abort();
        }

        i++;
        sleep(1);
    }   
    return 0;
}

输出结果: 

do working 1
do working 2
do working 3
do working 4
Aborted (core dumped)

使用alarm设置超时 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

//测试alarm函数
int main(void){
    unsigned int ret = 0;
    
    //第一次设置闹钟 5秒钟之后就超时 发送对应信号
    ret = alarm(5);

    printf("last alarm left time is %u\n",ret);
    
    sleep(2);
    //之前没有超时的闹钟被新的设置给覆盖
    ret = alarm(3);
    printf("last alarm left time is %u\n",ret);

    printf("press any buton continue..\n");
    getchar();
    return 0;
}

last alarm left time is 0
last alarm left time is 3
press any buton continue..
Alarm clock

 定时 与进程状态无关 无论进程处于任何状态 alarm都计时

setitimer定时器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>


int main(void){
    int ret = -1; 
    struct itimerval tmo;

    tmo.it_value.tv_sec = 3;
    tmo.it_value.tv_usec = 0;

    tmo.it_interval.tv_sec = 2;
    tmo.it_interval.tv_usec = 0;

    ret = setitimer(ITIMER_REAL, &tmo, NULL);
    if(-1 == ret){
        perror("setitimer");
        return 1;
    }   

    printf("press any button to continue...\n");
    getchar();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43754049/article/details/126146318