- 相关接口
pause 函数用于将进程挂起. 如果信号的处理动作是终止进程, 则进程终止, pause 函数没有返回值; 如果信号的处理动作是忽略, 则进程被挂起, pause函数不返回, 如果信号的处理动作是捕捉, 则调用信号处理动作之后pause 返回 -1. - 来看一段代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void sig_alarm(int seconds)
{}
int mysleep(int seconds)
{struct sigaction act;struct sigaction oact;int unslept = 0;act.sa_handler = sig_alarm;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigemptyset(&oact.sa_mask);sigaction(SIGALRM, &act, &oact);alarm(seconds);pause();unslept = alarm(0);sigaction(SIGALRM, &oact, NULL);
}
int main()
{while(1){mysleep(5);printf("5 seconds after\n");}return 0;
}
上面代码是用来自主实现一个 sleep 函数. 先将 SIGALRM 信号注册,然后设定一个闹钟, 接着系统调用 pause 函数等待, 在 nsecs 秒之后, 闹钟设定的时间到了, 此时内核给进程发送一个 SIGALRM 信号, 当内核正要切回到用户态时, 发现一个可以递达的信后 SIGALRM, 它的处理动作是 sig_alrm, 此时内核有切回到 这个函数处取执行该信号的自定义动作, 在处理 sig_alrm 函数时, 系统将 SIGALRM 信号屏蔽, 当处理完这个函数时, 对 SIGALRM 函数解除屏蔽, 同时系统通过调用 sigreturn 函数返回到内核态, 接着从内核态返回到 主控制流处, 执行剩余的代码
(1)也许会有人问信号处理 sig_alrm 函数时什么都没有干为什么还要注册, 原因很简单, 如果对 SIGALRM 信号不注册, 当注册一个 5 秒的闹钟信号时,5 秒之后该信号会被递达, 而此时的信号没有注册,信号的处理动作将会是终止进程, 此时进程终止, 程序退出, 而我们要实现的是将进程睡眠 5 秒钟, 那不就和我们的目的有冲突了吗?
(2)也许还会有人问, 为什么在sleep函数之后需要对 SIGALRM 信号的默认处理动作进行恢复, 原因很简单. 加入这个代码很长, 而我们在 sleep 函数之后系统又用到了 SIGALRM 信号, 而此时我们的目的是在 n 秒之后操作系统给进程发送一个 SIGALRM 信号来终止信号, 而此时我们没有将该信号的处理动作进行恢复, 进程会去执行 sig_alrm 函数, 此时进程就不会在 5 秒之后退出
3. 可重入函数
(1)定义 :
重入的意思就是函数在被不同的执行流调用, 有可能在第一个执行流还没有执行完的时候又被第二个执行流调用. 而此时可能会由于重入导致一些错误, 此时的函数称为不可重入函数, 而当第一个执行流还没有执行完时, 第二个执行流进入, 此时没有导致函数执行功能发生错误, 此时这个函数就叫做可重入函数.
(2)条件:
如果一个函数调用了 malloc , free, 或者标准库 I/O函数,等全局变量的时候这个函数就叫做不可重入函数, 而如果一个函数只调用了自己的局部变量, 此时的函数叫做可重入函数,因为系统函数和主控制流各自独立拥有自己的堆栈, 不存在调用关系, 因此两个互不干扰