使用信号唤醒休眠函数,休眠函数手动重启,休眠函数自动重启(信号)【linux】(zu)

使用信号唤醒休眠函数

会导致休眠的函数

我们调用sleep、pause等函数时,这些函数会使进程进入休眠状态,如果你不想继续休眠可以使用信号将其唤醒。

为什么要捕获信号呢?

如果信号的默认处理方式是终止,我们并没有把函数唤醒,倒是把整个进程终止了。

唤醒的方法

给信号登记一个空捕获函数即可,当然你也可以在捕获函数写你要的代码,不过如果仅仅只是用于唤醒的话,捕获函数的内容一般都是空的。

唤醒的过程

当信号发送给进程后,会中断当前休眠的函数,然后去执行捕获函数,捕获函数执行完毕返回后,不再调用休眠函数,而是执行休眠函数之后的代码,这样函数就被唤醒了。

我想继续休眠怎么办?

我希望长期休眠的,但是不小心被别人发送的信号给唤醒了,我想继续休眠怎么办?

手动重新启动休眠函数(重新调用休眠函数)

pause()函数唤醒过程

代码演示:

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

void signal_fun()
{
        printf("time up\n");
}

int main(int argc, char **argv, char **environ)
{
        signal(SIGINT,signal_fun);
        pause();
        printf("hello\n");
        while(1);
        return 0;
}

运行结果为:

在这里插入图片描述

进程在pause休眠,按下ctrl+c之后,pause函数就会被中断,并且调用捕获函数,然后捕获函数执行之后返回继续执行pause函数之后的代码,打印出来hello进入while循环,再次按下ctrl+c继续调用捕获函数进行打印。

sleep函数唤醒过程

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

void signal_fun()
{
        printf("time up\n");
}

int main(int argc, char **argv, char **environ)
{
        signal(SIGINT,signal_fun);
        sleep(10);
        printf("hello\n");
        while(1);
        return 0;
}

运行结果为:

在这里插入图片描述

如果sleep函数休眠的过程中按下ctrl+c发送信号,就会中断sleep函数,然后去执行捕获函数,捕获函数在运行完成之后,继续执行sleep函数之后的代码。

手动重启pause函数

那么如果不想唤醒上面sleep和pause。但是又需要SIGINT信号需要被捕获,那么接下来我们手动重启调用:

pause函数会返回:当一个信号被捕获,而且信号捕获函数有返回。我们或者在信号捕获函数写入代码return 或者不写也会自动返回,但是如果信号捕获函数里面是exit(0),那么进程被终止,信号捕获函数也就不会有返回值。这种情况下pause函数返回-1并且errno被设置为EINTR。

EINTR说明:当一个信号被捕获,而且信号捕获函数有返回的时候产生,说明的是当前pause函数被信号中断。

那么接下来我们进行代码演示进行手动重启:
代码演示:

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

void signal_fun()
{
        printf("time up\n");
}

int main(int argc, char **argv, char **environ)
{
        int ret = 0;
        signal(SIGINT,signal_fun);
lable:  ret = pause();
        if(ret == -1&& errno ==EINTR)
        {
                goto lable;
        }
        printf("hello\n");
        while(1);
        return 0;
}

运行结果为:
在这里插入图片描述

我们可以看到不会打印hello 那么也就不会执行pause下面的代码。

手动重启sleep函数

我们首先查看一下sleep函数的返回值:
如果设置的时间到了,返回为0,如果sleep被信号中断就返回剩余的秒数。
代码演示:

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

void signal_fun()
{
        printf("time up\n");
}

int main(int argc, char **argv, char **environ)
{
        int ret = 0;
        signal(SIGINT,signal_fun);
        ret = 10;
lable:  ret = sleep(ret);
        if(ret != 0)
        {
printf("ret = %d\n",ret);
                goto lable;
        }
        printf("hello\n");
        while(1);
        return 0;
}

运行结果为:
在这里插入图片描述

上面的过程总共休眠10秒钟。
当你的休眠函数不希望被信号个打断时,我们就可以重启这个函数的调用。

休眠函数自动重启

比如使用read从键盘读取数据,当键盘没有输入任何数据时,read会休眠,不过函数被信号唤醒后,会自动重启read的调用。

read函数读数据时,并不一定会休眠,读硬盘上的普通文件时,不管文件有没有数据,read都不会休眠,而是会返回继续向下运行,如果read读的是键盘的话,如果键盘没有数据时read就会休眠。

当read函数休眠时,如果被信号唤醒了,当捕获函数返回后,read会自动重启。

代码演示;

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

void signal_fun(int signo)
{
        printf("!!!!!\n");
}

int main(int argc, char **argv, char **environ)
{
        int ret = 0;
        signal(SIGINT,signal_fun);
        char buf[100] = {0};
        read(0,buf,sizeof(buf));
        printf("hello\n");
        return 0;
}

运行结果为:

在这里插入图片描述

我们可以看到,按下键盘ctrl+c之后当raed函数在收到信号,执行完信号捕获函数之后会继续重新调用read,而不会执行read后面的代码,所以不会打印出来helloworld。

输入数据的时候hello就会被打印出来,读取到数据read函数执行完成了,就会继续执行read函数之后的代码:
在这里插入图片描述

小结

我们不需要记住那些函数是需要手动重启的,只需要记住,对于绝大多数休眠函数来说,被信号中断后,如果你想继续休眠的话,需要自己去手动重启,否则就会继续向后运行。

如果你拿不准是自动重启的,还是需要手动重启的,有两个方法来判断:
自己去测试一下,如果被信号中断后,后续代码不会被执行的,就是自动的重启的,否者就是手动重启。

看函数手册里面返回值的描述,如果描述里面有明确说明该函数可以被信号中断的话,这个函数就是手动重启。

发布了163 篇原创文章 · 获赞 94 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43648751/article/details/104670137