sigsuspend/sigaction

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);
}

代码的其余部分不变

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值