10 Linux 学习---信号(下)

一.信号处理常见函数:

  .signal 函数   

        typedef void (*sighandler_t)(int);

           sighandler_t signal(int signum, sighandler_t handler);

   说明: 次函数为信号处理函数 或者 信号扑捉函数

  2.  kill 和 raise 函数

       #include <signal.h>

       int kill(pid_t pid, int sig);

  说明: 将信号发送给进程或者进程组。

       int raise(int sig);

  说明: 允许进程向自身发送信号。 等价于调用 kill(getpid(),signo);

  3.alarm  和  pause

       #include <unistd.h>

       unsigned int alarm(unsigned int seconds);

  说明:使用这个函数可以设置一个计时器,在某个指定时间产生SIGALRM信号 

  int pause(void);

  说明:使调用进程挂起直至捕捉到一个信号。

  4.信号集--- 数据类型

    #include <signal.h>

       int sigemptyset(sigset_t *set);
 //将信号集初始化为空

       int sigfillset(sigset_t *set);          //将信号集初始化为包含所有已定义的信号

       int sigaddset(sigset_t *set, int signum);   ///添加一个信号到信号集

       int sigdelset(sigset_t *set, int signum);   //  从信号集中删除一个信号

       int sigismember(const sigset_t *set, int signum);  // 判断一个给定的信号是否是一个信号集的成员

  5.sigprocmask 函数

         #include <signal.h>

       int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);


  说明: 信号屏蔽的设置函数

         SIG_BLOCK  --把参数set中的信号添加到信号屏蔽字中

         SIG_SETMASK -- 把信号屏蔽字设置为参数set中的信号

         SIG_UABLOCK  --从信号屏蔽字中删除参数set中的信号

  6.sigpending 函数

       #include <signal.h>

       int sigpending(sigset_t *set);

  说明: 返回信号集,

  7. sigaction 函数

       #include <signal.h>

       int sigaction(int signum,      /// 被处理的信号

                        const struct sigaction *act,  ///处理函数及其参数
                     struct sigaction *oldact);  //返回原来的处理函数

  说明: 检查,修改与指定信号相关联的处理动作。

           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

  8.sigsuspend 函数

         #include <signal.h>

       int sigsuspend(const sigset_t *mask);

  说明: 将进程的信号屏蔽字设置为由mask 指向的值。在捕捉到一个信号或者发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将进程的信号屏蔽字设置为调用sigsuspend 之前的值


几个经典案例程序:

案例1: 写一个程序,只要有信号触发,程序将退出

#include <unistd.h>
#include <signal.h>
#include <stdio.h>


/// 信号处理函数
void deal(int s)
{
	printf("有信号!\n");
}

int main()
{
	sigset_t new,old;
	struct sigaction act;
	act.sa_handler = deal; // 绑定信号处理函数
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGINT,&act,0);// 准备扑捉SIGINT信号
	sigemptyset(&new);
	sigaddset(&new,SIGINT);
	sigprocmask(SIG_BLOCK,&new,&old); // 将SIGINT信号阻塞,同时保存到当前信号
	printf("SIG_BLOCK");
	sigprocmask(SIG_UNBLOCK,&old,NULL);// 取消阻塞
	//pause();
	sleep(5);
	return 0;
}

解析:结果发现,程序一直处于挂起状态。在取消阻塞和 pause()函数之间有个临界区域执行码,使程序处理一直挂起状态。

案例2: 使用sigsuspend() 函数解决上述问题



#include <unistd.h>
#include <signal.h>
#include <stdio.h>


void deal(int s)
{
	if(s== SIGINT)
		printf("信号SIGINT\n");
	else if(s == SIGQUIT)
		printf("信号SIGQUIT\n");
	else
		printf("信号SIGUSR1\n");
}

int main()
{
	sigset_t new,old,wait; // 三个信号集
	struct sigaction act;
	
	act.sa_handler = deal;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	sigaction(SIGINT,&act,0); // 可以捕捉到3个信号SIGINT/SIGQUIT/SIGUSR1
	sigaction(SIGINT,&act,0);
	sigaction(SIGINT,&act,0);
	
	sigemptyset(&new);
	sigaddset(&new,SIGINT); // 把SIGINT信号加载到new信号集中
	sigemptyset(&wait);
	sigaddset(&wait,SIGUSR1); 
	sigprocmask(SIG_BLOCK,&new,&old); // 将SIGINT信号阻塞,保存在当前信号old
	// 临界区执行
	if( sigsuspend(&wait) != -1)
	{
		printf("sigsuspend 错误!\n");
	}
	sigprocmask(SIG_SETMASK,&old,NULL);
	return 0;
}

解析:if(sigsuspend(&wait) != -1) 

程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1信 号,阻塞掉,程序继续挂起;过来其他信号,例如SIGINT,则会唤醒程序。执行sigsuspend的原子操作。注意:如果“sigaddset(&wait,SIGUSR1);”这句没有,则此处不会阻塞任何信号,即过来任何信号均会唤醒程序。

sigsuspend的原子操作是

1)设置新的mask阻塞当前进程(上面是用wait替换new,即阻塞SIGUSR1信号)

(2)收到SIGUSR1信号,阻塞,程序继续挂起;收到其他信号,恢复原先的mask(即包含SIGINT信号的)。

(3)调用该进程设置的信号处理函数(程序中如果先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,因为SIGUSR1是前面阻塞的)

(4)待信号处理函数返回,sigsuspend返回了。(sigsuspend将捕捉信号和信号处理函数集成到一起了)

案例3:(集中处理外部中断)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


void deal(int s)
{
	printf("外部中断处理中..... \n");
	sleep(3);
	printf("外部中断处理完毕!\n");
}

main()
{
	int i;
	 sigset_t new,old;
	 sigemptyset(&new);
	 sigemptyset(&old);
	 
	 sigaddset(&new,SIGINT);
	 signal(SIGINT,deal);
	 sigprocmask(SIG_BLOCK,&new,0);
	 for(i=1; i<=10; ++i)
	 {
	 	printf("正在拷贝文件<%d>!\n",i);
	 	sleep(3); 
	 	printf("拷贝文件<%d> 完毕!\n",i);
	 	 
	 	 sigpending(&new);//函数返回在送往进程的时候被阻塞挂起的信号集合
	 	if( sigismember(&new,SIGINT))
	 	{
	 		sigsuspend(&old);
	 	}
	 }
	 printf("所有文件拷贝完毕\n");
	 sigprocmask(SIG_UNBLOCK,&new,0);
	 printf("over!\n");
}

调试结果:


案例4: 

   1.使用sigaction 处理信号,使用kill 发送信号

   2.使用sigacction 处理信号,使用sigqueue 发送信号

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void deal(int s)
{
	printf("外部中断处理中..... \n");
	sleep(3);
	printf("外部中断处理完毕!\n");
}


main()
{
	struct sigaction act = {0};
	act.sa_handler = deal;
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask,SIGINT);
	act.sa_flags = 0;
	sigaction(SIGUSR1,&act,0);
	while(1);
}

先运行程序,打开另外一个终端,给这个运行的程序发送信号SIGUSR1,

---------------------------------------

$ kill -USR1 12771
$ kill -INT 12771

------------------------------------------------------------------


   





   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值