进程间通讯 (IPC 技术) - 信号

IPC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法。在Linux C编程中有几种方法

(1) 半双工Unix管道

(2) FIFOs(命名管道)

(3) 消息队列

(4) 信号量

(5) 共享内存

(6) 网络Socket

1. 信号  (该文章信号是Ubuntu Linux 虚拟机环境下)

在 Ubuntu   中   

kill -n    发送第 N 个信号   比如第九个 是 杀死

1~ 31 不可靠信号    34~64 可靠信号

其中  SIGUSR1  与  SIGUSR2  可以用户自定义;  

void (* functon)(int)   函数指针         名称在后面的就是该数据的属性

1.1signal库函数

        如果想让程序能够处理信号,可以使用 signal库函数,要引入头文件<signal.h>

void (*signal(int sig, void (*func)(int))) (int);

void (*func)(int) 是函数指针

其中int 形参 可以用来判断信号ID;

        配合kill 使用   , signal绑定信号与函数指针, 使用kill 发送给进程;

    kill( 进程ID ,  信号 );  //发送信号给目标进程

特点: 

1. 优先级最高,可以打破死循环先执行信号中函数指针的内容,再回去继续进行死循环。

2. 接收的信号没有绑定函数, 会导致进程直接结束代码, 但是进程不会结束,子进程的话会进入僵尸状态。

3. 不可靠信号,如果连续发送太快进程在执行会不管新接收的信号, 一次只处理一条信号。可靠信号就没这个问题。

4. 进程接受到的信号无法识别执行什么,就会意外结束程序, 如果在子进程当中可能会引起僵尸状态。

2.1  无参信号:头文件如果不知道 在Ubuntu 终端中使用   man  函数名       来查询)

        signal 与 kill 配合

//信号方案1     不带参
	
	signal(SIGUSR1, signal_funtion);

	pid_t id = 0;
	id = fork();
	int state = 0;
	if ( id > 0 )
	{
		sleep(5);
		for (int i = 0; i < 3 ; i++)
		{
			sleep(2);
			//给子进程 id 发送信号
			kill(id, SIGUSR1);
		}
		//接收子进程状态
		wait(&state);
		while (true)
		{
		}
	}
	else
	{
		while (1)
		{
			sleep(1);
			cout << "子进程: " << getpid() << endl;
		}
		exit(1);
	}

2.2 带参信号:(Ubuntu 目前只能发送int数据)

  sigaction 与 sigqueue      (该组合也可进行无参信号发送,就是没有signal 方便)

        union sigval  该结构体就是传递的带参, 其中只有int能用,  另一个保留的void *参数 暂时官方没完善用不了。


	//信号方案2   带参信号
	
	pid_t id = 0;
	int state = 0;
	struct sigaction act;
	
	act.sa_sigaction = sigaction_function;
	act.sa_flags = SA_SIGINFO; //表示设置为带参信号
	


    /*   
        //这是不带参的写法
        struct  sigaction act2;
	    act2.sa_handler = test2;
	    act2.sa_flags = 0;
    */
    

    sigaction(SIGUSR1, &act, NULL);   //绑定信号

	//子进程在信号之后生成
	id = fork();
	if ( id > 0 )
	{
		sleep(5);
		for (int i = 0; i < 3 ; i++)
		{
			sleep(2);
			union sigval value;
			value.sival_int = 123;
			//给子进程 id 发送信号
			sigqueue(id, SIGUSR1, value);
		}
		//接收子进程状态
		wait(&state);
		while (true)
		{
		}
	}
	else
	{
		while (1)
		{
			sleep(1);
			cout << "子进程: " << getpid() << endl;
		}
		exit(1);
	}

2.3  信号冲突:  ※

        两个及以上的命令互相影响,造成程序异常。

    信号冲突有两种情况:

        不过只解决异种信号冲突的情况, 同种信号(同一个重复发送)会自动排队运行。

//这两个函数绑定 10 与  12 信号  用来测试信号冲突
void test1( int num )
{
	cout << " test1 run : " << getpid() << endl;
	sleep(20);
	cout << " test1 over " <<  endl;
	
}
void test2(int num)
{
	cout << " test2 over " << endl;
}

//信号冲突   (两个信号及以上, 执行一个信号的时候另外的信号也传递过来互相影响)
	
	/*
		两种情况
		情况1 :
		※情况1:一个信号正在执行处理函数,还在执行没做完,接收到异种信号,
			执行函数被打断立刻执行异种信号处理,异种处理完再回去处理未处理完的第一个信号的逻辑
		情况2:一个信号正在执行处理函数,还在执行没做完,接到铜钟信号,
			执行函数继续执行,完成之后再次下一次函数

		口诀: 异种打断, 同种排队
	*/
	struct  sigaction act1;
	act1.sa_handler = test1;
	act1.sa_flags = 0;

	struct  sigaction act2;
	act2.sa_handler = test2;
	act2.sa_flags = 0;

    //清空信号集
	sigemptyset( &(act1.sa_mask) );
	//添加信号集 把SIGUSR2 加到
	//sa_mask  
	/*sigset_t sa_mask 是一个信号集,在调用该信号捕捉函数之前,
		将需要block的信号加入这个sa_mask,仅当信号捕捉函数正在执行时
		,才阻塞sa_mask中的信号,当从信号捕捉函数返回时进程的信号屏蔽字复位为原先值。*/
	sigaddset(&(act1.sa_mask) , SIGUSR2);
	

	sigaction(SIGUSR1 , &act1, NULL);
	sigaction(SIGUSR2, &act2, NULL);
	
	while (1)
	{
		cout << " 进程正在运行: pid =  " << getpid() << endl;
		sleep(1);
	}

2.4  信号未绑定函数指针  (未决信号)

 //信号没绑定方法解决方法   使用信号集过滤掉

	sigset_t s;  // 定义一个信号集
	sigemptyset(&s);    //清空信号集
	sigaddset(&s, SIGUSR1);    //添加信号集
	sigaddset(&s, SIGUSR2);	   //添加信号集
	//启用信号集过滤
	if ( sigprocmask(SIG_BLOCK, &s, NULL) < 0 )
	{
		perror(" sigprocmask error! ");
	}
	while (1)
	{
		cout << " 进程正在运行 ... pid =  " << getpid() << endl;
		sleep(1);
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值