linux中进程间通讯-信号

1.知识点
         信号的收发
         信号的几种响应方式:
              第一种:默认响应方式
              第二种:程序员指定响应方式
              第三种:信号的忽略
              第四种:信号的阻塞(屏蔽)
   2.引入信号
          生活中的例子:大脑接收外界的红绿灯信号,控制大脑做不同的事情
          linux中的进程:也能接收外界发送的信号,控制进程做出不同的行为
     linux系统提供的信号 
          kill -l  查看所有的信号(62个信号)
          2) SIGINT     导致程序终止
          3) SIGQUIT    终止
          9) SIGKILL    终止
          18) SIGCONT    继续
          19) SIGSTOP    暂停
     linux提供两个常用命令用来给进程发送信号
          第一个: kill命令
                   kill  -信号的名字  进程的ID
                   kill  -信号的序号  进程的ID
                   比如: kill  -STOP  进程ID
                          kill  -19    进程ID
          第二个: killall命令
                   killall  -信号的名字  进程的名字
                   killall  -信号的序号  进程的名字
                   比如: killall  -STOP  进程名字
                          killall  -19    进程名字
   3.linux跟信号有关的接口函数
         总结信号的响应动作
            第一种:默认动作(linux系统已经规定好的动作)
                    绝大部分信号都会终止你的进程
            第二种:程序员可以改变信号的响应动作
                    注意:SIGKILL和SIGSTOP信号不能改变默认动作
            第三种:程序员可以使用signal函数去忽略信号
            第四种:程序员可以阻塞信号

         (1)发送信号
                #include <signal.h>
                int kill(pid_t pid, int sig);
                     返回值:成功 0  失败 -1
                       参数: pid --》进程的ID
                             sig --》你要发送的信号的序号/名字
         (2)捕捉信号,并改变信号的响应动作(重点)
                void (*signal(int sig, void (*func)(int)))(int);
                 简化写法:void (*signal(参数1,参数2))(int);
                 再简化:  void (*函数名字())(int);
                 signal(你要捕捉的信号,捕捉到这个信号以后做什么事情);
                       返回值:也是一个函数指针,类型跟第二个参数一样
                         参数:sig --》你要捕捉的信号
                               void (*func)(int) --》函数指针,用来表示信号的响应动作
                                       参数: int --》你捕捉到的信号的序号   
                 用法一:signal可以改变信号的响应动作
                 用法二:忽略信号SIG_IGN(左耳进右耳出,信号发过来,当作不存在)
                         注意:SIGKILL和SIGSTOP信号不能忽略
                 用法三:按照信号的默认动作响应SIG_DFL 
          (3)阻塞当前进程,等待信号的到来
                 int pause(void);
          (4)另外一组信号的发送和捕捉函数
                 两组常用的信号发送和捕捉函数
                     第一组:kill()和signal()
                     第二组:sigqueue()和sigaction()
                 发送信号(携带额外数据,买一送一):
                     int sigqueue(pid_t pid, int sig, const union sigval value);
                            参数:前面两个跟kill参数一样
                                  value --》存放你要发送给进程的额外数据
                                  union sigval {
                                      int   sival_int;  //发送一个整数给进程
                                      void *sival_ptr;  //发送一个地址给进程
                                  };
                 捕捉信号,改变信号的响应动作
                      int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
                             参数:sig --》你要捕捉的信号
                                   act --》
                                       struct sigaction
                                       {
                                            void(*sa_handler)(int)   //函数指针,跟signal的功能一模一样 
                                            sigset_t  sa_mask        //???
                                            int  sa_flags    //标志位,设置0表示选择sa_handler作为信号的响应函数
                                                                      设置SA_SIGINFO表示选择sa_sigaction作为信号的响应函数                                                 void(*sa_sigaction) (int,siginfo_t *,void *); //函数指针  
                                       }
                                        void(*sa_sigaction) (int,siginfo_t *,void *)
                                               参数: int --》信号的序号
                                                      siginfo_t --》结构体,存放收到的额外数据
                                                      {
                                                           si_int;  //对应额外数据中的那个整数
                                                           si_ptr;  //对应额外数据中的那个指针
                                                      }
                                   oact --》用来备份之前的设置,一般设置为NULL 
            (5)阻塞信号(屏蔽信号)
                    概念:当信号发送给进程的时候,该进程把信号挂起(暂时把信号挡住,不去响应该信号)
                    sigset_t类型:称之为信号阻塞掩码集(多个信号的一个集合,你把要屏蔽的信号存放到这个集合中,然后设置阻塞即可)

                     int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
                                参数:how --》SIG_BLOCK    //设置信号阻塞
                                              SIG_UNBLOCK  //解除信号的阻塞
                                      set --》存放你想阻塞的所有信号
                                      oset --》备份
                     如何把需要阻塞的信号添加到集合中去???
                             int sigemptyset(sigset_t *set); //清空集合set

                             int sigfillset(sigset_t *set);  //把linux中所有信号一次性加入到集合set中

                             int sigaddset(sigset_t *set, int signum); //把signum这个信号添加到集合set中

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

                             int sigismember(const sigset_t *set, int signum); //判断signum这个信号在不在集合set中
                                                                                 是成员      返回1
                                                                                 不在集合中  返回0

#include "myhead.h"

int main(int argc,char **argv)
{
	//通过主函数传参把另外一个进程的ID号传递过来
	//主函数传参传递过来的都是字符串,但是ID要求是整数
	//int atoi(const char *nptr); 可以把字符串转换成整数
	kill(atoi(argv[1]),9);  //发送9号信号SIGKILL
}

 

#include "myhead.h"

int main()
{
	printf("该进程的ID是:%hu\n",getpid());
	while(1)
	{
		printf("外界可以控制这个进程!\n");
		sleep(1);
	}
}

signal忽略信号

#include "myhead.h"

int main()
{
	printf("程序已经跑起来了!\n");
	
	//signal函数忽略一些信号
	signal(SIGQUIT,SIG_IGN);
	signal(SIGINT,SIG_IGN);
	signal(SIGKILL,SIG_IGN);  //KILL信号不能忽略,写了不起作用
	signal(SIGSTOP,SIG_IGN);  //STOP信号不能忽略,写了不起作用
	
	//while(1);  //老土的做法,防止程序退出
	//阻塞进程,等待信号的到来
	pause();
}

signal捕捉信号并改变信号的相应动作

#include "myhead.h"

//自定义函数表示信号的响应动作
void fun(int sig)
{
	printf("我捕捉到信号了!信号的序号:%d\n",sig);
}

void otherfun(int sig)
{
	printf("我捕捉到信号了!信号的序号:%d\n",sig);
}

int main()
{
	printf("程序已经跑起来了!\n");
	
	//signal函数去捕捉SIGQUIT,改变SIGQUIT信号的响应动作
	signal(SIGQUIT,fun);
	//signal函数去捕捉SIGINT,改变SIGINT信号的响应动作
	signal(SIGINT,otherfun);
	signal(SIGKILL,fun);  //KILL信号不能改变默认动作
	signal(SIGSTOP,fun);  //STOP信号不能改变默认动作
	
	
	while(1);  //防止程序退出
}

信号的屏蔽

#include "myhead.h"

int main()
{
	//第一步:定义sigset_t变量,把你要屏蔽的信号加入到该集合中
	sigset_t myset;
	//清空集合
	sigemptyset(&myset);
	//添加你想要屏蔽的信号--》2  3  4三个信号屏蔽
	sigaddset(&myset,SIGINT);
	sigaddset(&myset,SIGQUIT);
	sigaddset(&myset,4);
	sigaddset(&myset,SIGKILL);  //不能屏蔽
	sigaddset(&myset,SIGSTOP);  //不能屏蔽
	//第二步:调用sigprocmask函数设置信号屏蔽
	sigprocmask(SIG_BLOCK,&myset,NULL);
	pause();
}

信号屏蔽只是暂时把信号挂起,等你解除屏蔽信号依然可以响应

#include "myhead.h"

int main()
{
	int i;
	//第一步:定义sigset_t变量,把你要屏蔽的信号加入到该集合中
	sigset_t myset;
	//清空集合
	sigemptyset(&myset);
	//添加你想要屏蔽的信号--》2 
	sigaddset(&myset,SIGINT);
	//第二步:调用sigprocmask函数设置信号屏蔽
	sigprocmask(SIG_BLOCK,&myset,NULL);
	//从下面这一行代码开始,不受SIGINT的影响
	for(i=0; i<10; i++)
	{
		printf("我有金钟罩,你发送INT信号弄不死我!\n");
		sleep(1);
	}
	//解除信号的屏蔽
	sigprocmask(SIG_UNBLOCK,&myset,NULL);
	printf("我还能正常运行吗?????\n");
	for(i=0; i<3; i++)
	{
		printf("还能响应INT信号吗\n");
		sleep(1);
	}
	
	pause();
}

sigqueue发送信息携带额外数据

#include "myhead.h"

int main(int argc,char **argv)
{
	union sigval myval;
	myval.sival_int=666; //给进程发送信号的同时,顺便发送一个整数
	
	sigqueue(atoi(argv[1])+65536,2,myval);
}

sigaction捕捉信号采用和signal一模一样的功能

#include "myhead.h"

//自定义信号的响应函数
void fun(int sig)
{
	printf("我捕捉的信号序号是:%d\n",sig);
}
int main()
{
	struct sigaction myact;
	bzero(&myact,sizeof(myact));
	//myact.sa_handler=fun;     //改变信号的响应动作
	//myact.sa_handler=SIG_IGN; //忽略信号
	myact.sa_handler=SIG_DFL;   //按照信号的默认动作
	myact.sa_flags=0;
	
	//捕捉INT信号
	sigaction(SIGINT,&myact,NULL);
	
	pause();
}

sigaction捕捉信号接收额外数据

#include "myhead.h"

//自定义信号的响应函数
void fun(int sig,siginfo_t *info,void *arg)
{
	printf("我捕捉的信号序号是:%d\n",sig);
	printf("我收到的额外数据是:%d\n",info->si_int);
}
int main()
{
	printf("进程的ID是:%hu\n",getpid());
	struct sigaction myact;
	bzero(&myact,sizeof(myact));
	myact.sa_sigaction=fun;
	myact.sa_flags=SA_SIGINFO;
	
	//捕捉INT信号
	sigaction(SIGINT,&myact,NULL);
	
	pause();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hqb_newfarmer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值