Linux学习(18):信号量-1

目录

1.信号的概念

1.1信号的5种默认处理动作 

2.各种函数

2.1 kill函数

2.2 raise函数

2.3 abort函数

2.4 alarm函数

2.5 setitimer函数

2.6 signal信号捕捉函数


1.信号的概念

 信号是一种异步通信的方式

 

 

 

 

1.1信号的5种默认处理动作 

2.各种函数

2.1 kill函数

        - 功能:给任何的进程或者进程组pid, 发送任何的信号 sig

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
    - 参数:
        - pid :
            > 0 : 将信号发送给指定的进程
            = 0 : 将信号发送给当前的进程组
            = -1 : 将信号发送给每一个有权限接收这个信号的进程
            < -1 : 这个pid=某个进程组的ID取反 (-12345)
        - sig : 需要发送的信号的编号或者是宏值,0表示不发送任何信号

    kill(getppid(), 9);//终止当前进程组
    kill(getpid(), 9);//终止当前进程
int main() {

    pid_t pid = fork();

    if(pid == 0) {
        // 子进程
        int i = 0;
        for(i = 0; i < 5; i++) {
            printf("child process\n");
            sleep(1);
        }

    } else if(pid > 0) {//注意的是,fork函数对父进程返回的是子进程的pid
        // 父进程
        printf("parent process\n");
        sleep(2);
        printf("kill child process now\n");
        kill(pid, SIGINT);
    }

    return 0;
}

2.2 raise函数

        - 功能:给当前进程发送任何信号

int raise(int sig);
    - 功能:给当前进程发送信号
    - 参数:
        - sig : 要发送的信号
    - 返回值:
        - 成功 0
        - 失败 非0

2.3 abort函数

- 功能: 发送SIGABRT信号(6)给当前的进程,杀死当前进程,产生core

void abort(void);

    kill(getpid(), SIGABRT);

2.4 alarm函数

    - 功能:设置定时器(闹钟)。函数调用,开始倒计时,当倒计时为0的时候,
            函数会给当前的进程发送一个信号:SIGALARM(14,定时器超时)

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
    - 参数:
        seconds: 倒计时的时长,单位:秒。如果参数为0,定时器无效(不进行倒计时,不发信号)。
                取消一个定时器,通过alarm(0)。
    - 返回值:
        - 之前没有定时器,返回0
        - 之前有定时器,返回之前的定时器剩余的时间

- SIGALARM :默认终止当前的进程,每一个进程都有且只有唯一的一个定时器。
    alarm(10);  -> 返回0
    过了1秒
    alarm(5);   -> 返回9

注意:alarm函数是非阻塞的

int main() {

    int seconds = alarm(5);
    printf("seconds = %d\n", seconds);  // 0

    sleep(2);
    seconds = alarm(2);    // 不阻塞
    printf("seconds = %d\n", seconds);  // 3

    while(1) {//10秒后被终止
    }

    return 0;
}

这里有个细节,第一次写没有两个\n,因此终端没有打印任何信息,这是因为linux需要换行符来刷新I\O缓冲区

    实际的时间 = 内核时间(1s) + 用户时间 + 消耗的时间
    进行文件IO操作的时候比较浪费时间

因此如果我们设置让进程运行一秒,期间伴随着用户态和内核态的切换以及I\O操作,所用的时间会不止一秒

2.5 setitimer函数

- 功能:设置定时器(闹钟)。可以替代alarm函数。精度微秒us,可以实现周期性定时

#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value,
                    struct itimerval *old_value);
    - 参数:
        - which : 定时器以什么时间计时
            ITIMER_REAL: 真实时间,时间到达后发送 SIGALRM   常用
            ITIMER_VIRTUAL: 用户时间,时间到达,发送 SIGVTALRM,只计算进程占用cpu的使用时间
            ITIMER_PROF: 以该进程在用户态和内核态下所消耗的时间来计算,时间到达,发送 SIGPROF


            ITIMER_REAL、ITIMER_VIRTUAL和ITIMER_PROF是Linux操作系统中的三个定时器类型,它们各自有不同的用途。
            1. ITIMER_REAL
            ITIMER_REAL用于设置一个实际时间计时器。当计时器到期后,会向进程发送SIGALRM信号。这种计时器通常用于在指定时间间隔内执行某些任务或超时检测。
            2. ITIMER_VIRTUAL
            ITIMER_VIRTUAL用于设置一个虚拟时间计时器。这种计时器只在进程运行用户空间程序代码(即CPU处于用户态)期间进行计数,当该计数达到设定值后,也会向进程发送SIGVTALRM信号。
            这种计时器通常用于测量进程使用CPU的时间片数量,并且可以防止某些恶意程序长时间占据CPU资源。
            另外需要注意,在多核处理器中,如果进程在不同的核心上运行,则ITIMER_VIRTUAL计时器只能记录当前正在使用 CPU 的那个核心上所花费的 CPU 时间,并不能记录整个进程占用 CPU 的总时间。
            3. ITIMER_PROF
            ITIMER_PROF是一个混合型定时器,在同时跟踪实际和虚拟处理时间方面都很有用。每次此类定制周期结束之前将生成 SIGPROF 信号并启动新周期。
            总结一下:
            - ITMER_REAL:实际物理时间。
            - ITMER_VIRTUAL:虚拟 CPU 时间。
            - ITMER_PROF: 实现了两者混合模式的功能

- *new_value: 设置定时器的属性,他是一个地址
            
    struct itimerval {      // 定时器的结构体
    struct timeval it_interval;  // 每个阶段的时间,间隔时间
    struct timeval it_value;     // 延迟多长时间执行定时器
    };

    struct timeval {        // 时间的结构体
        time_t      tv_sec;     //  秒数     
        suseconds_t tv_usec;    //  微秒    
    };

过10秒后,每个2秒定时一次
           
- old_value :记录上一次的定时的时间参数,一般不使用,指定NULL
        
- 返回值:
成功 0
失败 -1 并设置错误号

测试代码

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

// 过3秒以后,每隔2秒钟定时一次
int main() {

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;


    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    getchar();//等待键盘输入

    return 0;
}

2.6 signal信号捕捉函数

    - 功能:设置某个信号的捕捉行为

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
    - 参数:
        - signum: 要捕捉的信号
        - handler: 捕捉到信号要如何处理
            - SIG_IGN : 忽略信号
            - SIG_DFL : 使用信号默认的行为
            - 回调函数 :  这个函数是内核调用,程序员只负责写,捕捉到信号后如何去处理信号。
            回调函数:
                - 需要程序员实现,提前准备好的,函数的类型根据实际需求,看函数指针的定义
                - 不是程序员调用,而是当信号产生,由内核调用
                - 函数指针是实现回调的手段,函数实现之后,将函数名放到函数指针的位置就可以了。

    - 返回值:
        成功,返回上一次注册的信号处理函数的地址。第一次调用返回NULL
        失败,返回SIG_ERR,设置错误号
            
SIGKILL(9) SIGSTOP(19)不能被捕捉,不能被忽略。

typedef void (*sighandler_t)(int);

定义了一个sighandler_t类型的函数指针,指向返回值为void,参数为int的一类函数,当然我们也可以自己写一个返回值为void,参数为int的函数,将函数的地址传递给signal函数

测试代码:

void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}

// 过3秒以后,每隔2秒钟定时一次
int main() {

    // 注册信号捕捉
    // signal(SIGALRM, SIG_IGN);   啥都不做
    // signal(SIGALRM, SIG_DFL);   默认,终止进程
    // void (*sighandler_t)(int); 函数指针,int类型的参数表示捕捉到的信号的值。
    signal(SIGALRM, myalarm);

    struct itimerval new_value;

    // 设置间隔的时间
    new_value.it_interval.tv_sec = 2;
    new_value.it_interval.tv_usec = 0;

    // 设置延迟的时间,3秒之后开始第一次定时
    new_value.it_value.tv_sec = 3;
    new_value.it_value.tv_usec = 0;

    int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
    printf("定时器开始了...\n");

    if(ret == -1) {
        perror("setitimer");
        exit(0);
    }

    getchar();

    return 0;
}
对于
void myalarm(int num) {
    printf("捕捉到了信号的编号是:%d\n", num);
    printf("xxxxxxx\n");
}
我们也可以用函数指针的方式去写
typedef void (*sighandler_t)(int);
    -定义一个sighanler_t的函数指针类型,指向一类返回值为void,参数为int的函数

int main(){

    sighandler_t func;
    func = myalarm;
    signal(SIGALRM,func);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值