• 信号(二)



    1.向另一个进程发送信号

    ①kill函数

    int kill(pid_t pid, int siq)
    pid>0 将信号sig发给pid进程
    pid=0 将信号sig发给同组进程
    pid=-1 将信号sig发送给所有进程,调用者进程有权限发送的每一个进程(除了1号进程之外,还有它自身)
    pid<-1 将信号sig发送给进程组是pid(绝对值)的每一个进程

    例:子进程向父进程(同组进程)发送信号

    void  myhandle(int num)
    {
    	if (num == SIGINT)
    	{
    		printf("recv signal SIGINT \n");
    	}
    	else if (num == SIGUSR1)
    	{
    		printf("recv signal SIGUSR1 \n");
    	}
    	else
    	{
    		printf("recv signal id num : %d \n", num);
    	}
    }
    
    
    int main(void)
    {
    
    	pid_t 	pid;
    	printf("main ....begin\n");
    	
    	if (signal(SIGINT, myhandle) == SIG_ERR)
    	{
    		perror("func signal err\n");
    		return 0;
    	} 
    	if (signal(SIGUSR1, myhandle) == SIG_ERR)
    	{
    		perror("func signal err\n");
    		return 0;
    	} 
    	
    	pid = fork();
    	if (pid == -1)
    	{
    		printf("fork err....\n");
    		return 0;
    	}
    	
    	//子进程向父进程发送信号
    	//子进程向同组进程发送信号
    	if (pid == 0)
    	{
    	    pid = getppid();
    		kill(pid, SIGUSR1); //向父进程发信号
            //向进程组发信号
    		kill(0, SIGUSR1);      //法一
            //pid = getpgrp();      //法二
    		//killpg(pid, SIGUSR1);
    		exit(0);
    	}
    	printf("sleep 函数执行完毕以后返回...\n");
    	return 0;
    }
    

    ②raise函数

    给自己发送信号。raise(sig)等价于kill(getpid(), sig);
    

    ③sigqueue函数

    int sigqueue(pid_t pid, int sig, const union sigval value) 价格
    功能 针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
    返回值 成功:0,失败:-1
    参数
    pid 指定接收信号的进程id
    sig 发送的信号
    value 信号传递的参数
    其中第三个参数为union sigval,下面是union sigval的内容:
    
    typedef union sigval
    { 
        int sival_int; 
        void *sival_ptr; 
    }sigval_t;      
    
    

    注:在下面介绍的sigaction()函数的第二个参数结构体参数中,第二个处理器函数siginfo_t参数下有一个sigval_t值。。。

    例:两个进程间通过 sigqueue 发送数据

    void myHandle_forsigaction(int signum, siginfo_t *s_t, void *p)
    {
    	int myint = 0;
    	printf("recv signum : %d \n", signum);
    	myint = s_t->si_value.sival_int;
    	printf("%d %d \n", myint, s_t->si_int );
    }
    
    
    int main(int argc, char *argv[])
    {
    	pid_t 	pid;
    	int ret = 0;
    	
    	struct sigaction act;
    	act.sa_sigaction = myHandle_forsigaction;
    	sigemptyset(&act.sa_mask);
    	
    	//准备接受额外数据
    	act.sa_flags = SA_SIGINFO;
    
    	if (sigaction(SIGINT, &act, NULL) < 0)
    		ERR_EXIT("sigaction error");
    		
    	pid = fork();
    	
    	if (pid == -1)
    	{
    		printf("fork err...\n");
    		return 0;
    	}
    	
    	if (pid == 0)
    	{
    		int i = 0;
    		/*
    		Teacher *t = (Teacher *)malloc(sizeof(Teacher));
    		memset(t, 0, sizeof(Teacher));
    		strcpy(t->name, "name");
    		t->age = 33;
    		*/
    		
    		
    		/*
             union sigval {
                 int   sival_int;
                 void *sival_ptr;
             }; */
             
    	   union sigval  mysigval;
    	   //mysigval.sival_ptr = (void *)&t;
    	   mysigval.sival_int = 222;	
    	
    		//kill(getppid(), SIGINT);
    		//带额外数据
    		for (i=0; i<10; i++)
    		{
    			ret  = sigqueue(getppid(), SIGINT, mysigval);
    			if (ret != 0)
    			{
    				printf("sigqueue .....\n");
    				exit(0);
    			}
    			else
    			{
    				printf("sigqueue...successs\n");
    				sleep(2);
    			}
    		}
    
    	}
    	else if (pid > 0)
    	{
    		for (;;)
    			pause();
    	}
    
    	return 0;
    }
    
    

    2.改变信号处置

    从上一节可知,信号抵达后,有着不同的处理方式,如 `SIG_DFL` :执行默认的方式; `SIG_IGN` :忽略;或者执行信号处理器程序(即程序员自己编写的程序)。
    首先介绍如何实现信号处理器程序。
    

    ①signal函数

    __sighandler_t signal(int signum, __sighandler_t handler);
    功能 忽略信号、设置信号默认处理或注册一个信号处理函数
    返回值 返回修改前的handler函数指针
    参数
    signum 信号类型
    handler 接收到指定信号时将要调用的函数

    例1:信号的安装(注册SIGINT)

    void handler(int num)
    {
    	printf("recv num:%d \n", num);	
    }
    
    
    void main()
    {
    	//注册一个信号
    	//SIGINT  是ctrl+c 会产生2号信号。。。 中断应用程序
    	signal(SIGINT, handler);
    	
    	while(1)
    	{
    		pause();
    	}
    	
    	printf("main...Begin\n");
    		
    }
    
    

    例2:信号的恢复

    int main(void)
    {
    	__sighandler_t oldHandle;       //保留原处理信号行为
    	printf("main ....begin\n");
    	oldHandle = signal(SIGINT, myhandle); 
    	if (oldHandle == SIG_ERR)
    	{
    		perror("func signal err\n");
    		return 0;
    	} 
    	
    	printf("if u enter a, reset signal \n");
    	while(getchar() != 'a')
    	{
    		;
    	}
    
        //键入a以后,信号的恢复 
    	//法一:恢复默认函数
    	/*
    	if (signal(SIGINT, oldHandle) == SIG_ERR)
    	{
    		perror("func signal err\n");
    		return 0;
    	}
    	*/
    	//法二:
    	if (signal(SIGINT, SIG_DFL) == SIG_ERR)
    	{
    		perror("func signal err\n");
    		return 0;
    	}
    		
    	while(1) ;
    	return 0;
    
    }
    
    

    ②sigaction函数

    int sigaction(int signum,const struct sigaction *act,const struct sigaction *old)
    功能 注册一个信号处理函数
    返回值 成功:0,失败:-1
    参数
    signum 信号类型
    act 指向结构sigaction的一个实例的指针
    old 保存原来对相应信号的处理
    第二个参数act包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些信号等等。下面是struct sigaction的内容:
    
    struct sigaction {
    	void (*sa_handler)(int);   //信号处理程序一: 不接受额外数据,同signal()的第二个参数
    	void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序二:能接受额外数据,和sigqueue配合使用 
    	sigset_t sa_mask; //定义一组信号,不允许中断此处处理程序的执行
    	int sa_flags; //影响信号的行为   SA_SIGINFO表示能接受数据
    	void (*sa_restorer)(void); //废弃
    };
    
    
    由于struct sigaction结构中信号处理程序一与之前在signal中介绍的处理函数相似,所以接下来介绍信号处理程序二的使用。
    第二个参数siginfo_t内容如下:
    
     siginfo_t {
                  int      si_signo;  /* Signal number */
                  int      si_errno;  /* An errno value */
                  int      si_code;   /* Signal code */
                  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 */
                  void *   si_addr;   /* Memory location which caused fault */
                  int      si_band;   /* Band event */
                  int      si_fd;     /* File descriptor */
                }
    

    注:
    ①si_code:表示信号来源,对于通过sigqueue()发送的实时信号来说,该字段为SI_QUEUE
    ②si_value:由进程使用sigqueue()发送信号时在value参数中指定

    ③signal()与sigaction()

    sigaction()是建立信号处理器的首选API,较之signal()可移植性更佳。而往往使用signal()将信号处置设置为SIG_IGN或SIG_DFL。
    

    例:用sigaction模拟signal函数

    void handler(int sig)
    {
    	printf("recv a sig=%d\n", sig);	
    }
    
    __sighandler_t my_signal(int sig, __sighandler_t handler)
    {
    	struct sigaction act;
    	struct sigaction oldact;
    	act.sa_handler = handler;
    	sigemptyset(&act.sa_mask);
    	act.sa_flags = 0;
    
    	if (sigaction(sig, &act, &oldact) < 0)
    		return SIG_ERR;
    
    	return oldact.sa_handler;
    }
    
    int main(int argc, char *argv[])
    {         
    	struct sigaction act;
    	sigset_t sa_mask;
    	
    	act.sa_handler = handler;
    	act.sa_flags = 0;
    	sigemptyset(&act.sa_mask);
    
    	//测试信号安装函数
    	//sigaction(SIGINT, &act, NULL);
    	
    	//模拟signal函数
    	my_signal(SIGINT, handler);
    
    	for (;;)
    	{
    		pause();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Worktile 技术架构概要
    开发,从未如此清晰
    花一分钟来看看Worktile是如何为团队协作而生的
    Worktile协同特色之二:任务看板管理
    Worktile协同特色之一:无处不在的关注
    老板的宽容是一味害人的毒药——慈不带兵,善不经商,这个社会的法则就是弱肉强食
    以大多数人的努力程度之低来看,根本还轮不到拼天赋。时间管理。薪水是最低级的目标。比薪水更重要的,是成长和成就自己的机会。
    小豆君:你的目标是让其它工具为你服务,你要踩在巨人的肩膀上创造世界(摒弃掉你的好奇心,千万不要去追求第三方类或工具是怎么实现的,这往往会让你收效甚微,其实,你只需要熟练掌握它的接口,知道类的目的即可,不可犯面向过程的毛病)
    周末没事干就看CSS JS Python ThinkPHP的书,照着例子运行就行,可以增强信心(还有QML,虚拟机运行Web。Windows核心编程,照着例子运行。没事看看socket和rest的例子和文档,还有POCO和BOOST)
    离开华为三年,我才真正认同狼性法则(目标导向,没有借口,都是为自己的懒惰与不肯死磕找借口)
  • 原文地址:https://www.cnblogs.com/EngineerZhang/p/9313699.html
Copyright © 2020-2023  润新知