1.一段代码存在的问题
因为操作是不原子的
void Handler(int n)
{
write(1, "!", 1);
}
int main()
{
int i;
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
signal(SIGINT, Handler);
while(1)
{
///阻塞信号
sigprocmask(SIG_BLOCK, &set, NULL);
for(i = 0; i < 5; i++)
{
write(1, "*", 1);
sleep(1);
}
write(1, "\n", 1);
//恢复信号
sigprocmask(SIG_UNBLOCK, &set, NULL);
//等待信号
pause();
}
return 0;
}
我们要实现的功能是当一行的*打印完之后,我们按下ctrl+c,才能继续打印
上面图片中出现的问题,在信号阻塞的时候,如果产生了信号,该信号被推迟直到解除了阻塞,所以该信号就好像发生在恢复信号和等待信号之间。如果在解除阻塞时候和pause之间确实发生了信号,那么可能该信号永远不可见,使得pause永远阻塞。
2.sigsuspend
为了纠正此问题,需要在一个原子操作中实现 先恢复信号屏蔽字,然后进程休眠,如果捕捉到一个信号,而且从该信号处理程序返回,则该函数返回
void Handler(int n)
{
write(1, "!", 1);
}
int main()
{
int i;
sigset_t set, unblock_set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
signal(SIGINT, Handler);
//先让不阻塞信号
sigprocmask(SIG_UNBLOCK, &set, NULL);
//把当前的状态保存到unblock_set中
sigprocmask(SIG_BLOCK, &set, &unblock_set);
while(1)
{
sigprocmask(SIG_BLOCK, &set, NULL);
for(i = 0; i < 5; i++)
{
write(1, "*", 1);
sleep(1);
}
write(1, "\n", 1);
//sigprocmask(SIG_UNBLOCK, &set, NULL);
//pause();
//原子化操作
sigsuspend(&unblock_set);
}
return 0;
}
3.sigaction
signal在多个信号,共用一个信号处理函数的时候会产生问题
signal也不能区分信号的来源
NAME
sigaction - examine and change a signal action
SYNOPSIS
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);//可以替换signal那个函数
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;//信号集类型 可以把某些信号block住
int sa_flags;
void (*sa_restorer)(void);
};
sa_mask specifies a mask of signals which should be blocked
这里可以获得信号的属性
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
}
4.一个简单的demo
以前写的一个令牌桶,来实行流量控制,现在用户态的一个ALRM信号,会干扰流量控制
解决
void AlarmAction(int nNum, siginfo_t *info, void *unuse)
{
int i;
//alarm(1);
//printf("**********************\n");
//只有内核态 才可以
if(SI_KERNEL == info->si_code)
for(i = 0; i < MYTBF_MAX; i++)
{
if(NULL != job[i])
{
job[i]->token += job[i]->cps ;
if(job[i]->burst < job[i]->token)
job[i]->token = job[i]->burst;
}
}
}
void ModuleUnload(void)
{
int i;
struct itimerval itv;
//signal(SIGALRM, SignalRes);
//alarm(0);
//对信号处理进行恢复
sigaction(SIGALRM, &oldsa, NULL);
//关闭alarm
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, NULL);
for(i = 0; i < MYTBF_MAX; i++)
{
free(job[i]);
}
}
void ModuleLoad(void)
{
//SignalRes = signal(SIGALRM, AlarmHandler);
//alarm(1);
//
struct sigaction sa;
struct itimerval itv;
//设置信号处理函数
sa.sa_sigaction = AlarmAction;
//设置flag 使用那个三参的函数指针
sa.sa_flags = SA_SIGINFO;
//不需要屏蔽任何mask
sigemptyset(&sa.sa_mask);
//指定信号
sigaction(SIGALRM, &sa, &oldsa);
//这个就是设置时间 自动形成一个alarm链条
itv.it_interval.tv_sec = 1;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 1;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, NULL);
Inited = 1;
//钩子函数
atexit(ModuleUnload);
}
代码的其余部分不变