例如:strtok 就是一个不可重入函数,因为 strtok 内部维护了一个内部静态指针,保存上一 次切割到的位置,如果信号的捕捉函数中也去调用 strtok 函数,则会造成切割字符串混乱, 应用 strtok_r 版本,r 表示可重入。
int pause(void)
int sigsuspend(const sigset_t *mask)
mysleep 实现,这种实现方式是否存在 BUG?
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_alrm(int signo) {
/* nothing to do */
}
unsigned int mysleep(unsigned int nsecs) {
struct sigaction newact, oldact;
unsigned int unslept;
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
alarm(nsecs);
pause();
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL);
return unslept;
}
int main(void) {
while(1){
mysleep(2);
printf("Two seconds passed\n");
}
return 0;
}
mysleep 改进版
unsigned int mysleep(unsigned int nsecs) {
struct sigaction newact, oldact;
sigset_t newmask, oldmask, suspmask;
unsigned int unslept;
/* set our handler,save previous information */
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
/* block SIGALRM and save current signal mask */
sigemptyset(&newmask);
sigaddset(&newmask, SIGALRM);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
alarm(nsecs);
suspmask = oldmask;
sigdelset(&suspmask, SIGALRM); /* make sure SIGALRM isn't blocked */
sigsuspend(&suspmask);/* wait for any signal to be caught */
/* some signal has been caught,SIGALRM is now blocked */
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL);/* reset previous action */
/* reset signal mask, which unblocks SIGALRM */
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return(unslept);
}
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void sys_err(char *str) {
perror(str);
exit(1);
}
void do_sig_child(int signo) {
int status;
pid_t pid;
while ((pid = waitpid(0, &status, WNOHANG)) > 0) {
if (WIFEXITED(status))
printf("child %d exit %d\n", pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
}
}
int main(void) {
pid_t pid;
int i;
//阻塞SIGCHLD
for (i = 0; i < 10; i++) {
if ((pid = fork()) == 0)
break;
else if (pid < 0)
sys_err("fork");
}
if (pid == 0) {
int n = 18; while (n--) {
printf("child ID %d\n", getpid());
sleep(1);
}
return i;
}else if (pid > 0) { //先设置捕捉
//再解除对SIGCHLD的阻塞
struct sigaction act;
act.sa_handler = do_sig_child;
sigemptyset(&act.sa_mask); act.sa_flags = 0;
sigaction(SIGCHLD, &act, NULL);
while (1) {
printf("Parent ID %d\n", getpid());
sleep(1);
}
}
return 0;
}
pid_t waitpid(pid_t pid, int *status, int options)
int sigqueue(pid_t pid, int sig, const union sigval value) union sigval {
int sival_int;
void *sival_ptr; };
void (*sa_sigaction)(int, siginfo_t *, void *)
siginfo_t {
int si_int;
void *si_ptr;
sigval_t si_value;
...
}
sa_flags = SA_SIGINFO
/* POSIX.1b signal */ /* POSIX.1b signal */ /* Signal value */
实例
read 阻塞时,信号中断系统调用:
本文介绍了可重入函数,信号引起的竞态和异步 I/O,SIGCHLD 信号处理,向想好捕捉函数传参,信号中断系统调用。
领取专属 10元无门槛券
私享最新 技术干货