40.Linux 信号通信

进程间不能通信,只有通过管道才能实现两个进程之间的通信。

 杀死进程的命令:kill 9 pid号

信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。

内核可以发送多少种信号?64

kill -l

命令:kill -9 pid

信号通信的框架

-信号的发送(发送信号进程):kill raise alarm

-信号的接收(接收信号进程):pause(),sleep  while(1)

-信号的处理(接收信号进程):signal

1.信号的发送(发送信号进程)

1、kill函数

所需头文件

#include <signal.h>

#include <sys/types.h>

函数原型int kill(pid_t pid,int sig);
函数传入值
pid正数:要接收信号的进程的进程号
0:信号被发送到所有和pid进程在同一个进程组的进程
-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)

sig:信号

函数返回值
成功:0
出错:-1

kill命令(实现过程一样)的程序实现实例:(int kill(pid_t pid, int sig);

要学到字符串转换为整型的函数(int atoi(const char *nptr);

查看运行时,程序的id号(ps -axj

#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
	int pid;
	int sig;
	if(argc<3)
	{
		printf("please input param");
		return -1;
	}
	sig=atoi(argv[1]);
	pid=atoi(argv[2]);
	printf("sig=%d,pid=%d\n",sig,pid);
	
	kill(pid,sig);


	return 0;
}

 执行结果如下:

进程a要发信号给进程b必然要告诉内核,信号相关的函数:kill函数,raise函数

2、raise函数

raise:(作用)发送信号给自己==kill(getpid(),sig);

所需要的头文件

#include <signal.h>

#include <sys/types.h>

函数原型int raise(int sig);
函数传入值sig信号
函数返回值成功:0
失败:-1

 例程raise函数的简单使用

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main()
{
	printf("raise before");
	raise(9);
	printf("raise aftre\n");
	return 0;
}

执行结果如下:

那为什么第一条“raise before”语句没有输出呢?

答: 因为printf这条语句没有加\n,对printf是一个库函数,有库缓存

raise作用:等于_exit(),没把库缓存写到内存里面就退出了,所以没有打印

(暂停信号)SIGTSTP信号:该信号用于暂停交互进程,用户可键入SUSP字符(通常是ctrl+z)发出这个信号。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        pid_t pid;
        pid=fork();
        if(pid>0)
        {
                sleep(8);
                if(waitpid(pid,NULL,0) == 0)
                {
                        kill(pid,9);
                }
                wait(NULL);
                while(1);
        }
        if(pid==0)
        {
                printf("raise function before\n");
                raise(SIGTSTP);
                printf("raise function after\n");
                exit(0);
        }
        return 0;
}

所以raise函数就是个给自己发信号的函数

alarm函数

信号:SIGALRM:该信号当一个定时器到时的时候发出。终止

alarm也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间到时,它向进程发送SIGALRM信号。如果忽略或者不捕获此信号,则其默认动作是终止调用该alarm函数的进程。

alarm与raise函数的比较:

相同点:让内核发送信号给当前进程

不同点:

1.alarm只会发送SIGALARM信号

2.alarm会让内核定时一段时间后发送信号,raise会让内核立刻发信号

所需头文件#include <unistd.h>
函数原型unsigned int alarm(unsigned int seconds);
函数传入值seconds:指定秒数
函数返回值成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0.
出错:-1

通过程序了解alarm信号通信的框架

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main()
{
	int i=0;
	printf("alarm before\n");
	alarm(9);
	printf("alarm aftre\n");
	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things,i=%d\n",i);
	}
	return 0;
}

执行结果如下:

 当收到alarm信号时终止进程

2.信号接收(接收信号进程)

接收信号的进程,要有什么条件:想要使接收的进程能收到信号,这个进程不能结束:sleep

 pause:使进程状态变为S(睡眠态

所需头文件#include <unistd.h>
函数原型int pause(void);
函数返回值成功:0,出错:-1

信号:SIGINT

该信号在用户键入INTR字符(Ctrl+C)时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程。

终止进程

pause(暂停):终止进程的执行

例子如下:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main()
{
	int i=0;
	printf("pause before\n");
	pause();
	printf("pause aftre\n");
	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things,i=%d\n",i);
	}
	return 0;
}

执行结果如下:

3.信号的处理(接收信号进程):signal

signal函数

自己的处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的处理方式

所需要的头文件#include <signal.h>

函数原型

void (*signal(int signum,void (*handler)(int)))(int);
函数传入值signum:指定处理信号
handler:SIG_IGN:忽略该信号
SIG_DFL:采用系统默认方式处理信号
自定义的信号处理函数指针(自己的函数)
函数返回值成功:设置之前的信号处理方式
出错:-1

对signal函数的分析

void (*signal(int signum,void (*handler)(int)))(int);

参数:A=void (*handler)(int)==一个函数指针变量,函数的形式:含有一个整型参数,返回值为空。

void (*signal(int signum,A(int);

signal:含有两个参数,第一个参数,信号值   第二个参数   函数指针

返回值:函数指针

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
void (*signal(int signum,void (*handler)(int)))(int);

内核收到alarm的信号以后会执行myfun里面的内容,执行完myfun里面的内容后,会返回main函数执行剩下的内容

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

void myfun(int signum)
{
	int i;
	i=0;
	while(i<10)
	{
		printf("process signal_signum=%d\n",signum);
		sleep(1);
		i++;
	}
	return;   //返回到main函数,执行剩下的内容
}

int main()
{
	int i=0;
	signal(14,myfun);
	printf("alarm before\n");
	alarm(9);
	printf("alarm aftre\n");
	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things,i=%d\n",i);
	}
	return 0;
}

执行结果如下:

 

 使用SIG_IGN的方式

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

void myfun(int signum)
{
	int i;
	i=0;
	while(i<10)
	{
		printf("process signal_signum=%d\n",signum);
		sleep(1);
		i++;
	}
	return;
}

int main()
{
	int i=0;
	signal(14,myfun);
	printf("alarm before\n");
	alarm(9);
	printf("alarm aftre\n");
	signal(14,SIG_IGN);

	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things,i=%d\n",i);
	}
	return 0;
}

执行结果如下:

 

 当使用默认处理方式时,SIG_DFL

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

void myfun(int signum)
{
	int i;
	i=0;
	while(i<10)
	{
		printf("process signal_signum=%d\n",signum);
		sleep(1);
		i++;
	}
	return;
}

int main()
{
	int i=0;
	signal(14,myfun);
	printf("alarm before\n");
	alarm(9);
	printf("alarm aftre\n");
	signal(14,SIG_IGN);
	signal(14,SIG_DFL);
	while(i<20)
	{
		i++;
		sleep(1);
		printf("process things,i=%d\n",i);
	}
	return 0;
}

执行结果如下:

 

例子:父子进程方式进行信号通信。

程序设计思路:调用fork函数后,程序分裂成一样两个程序,父进程中每秒打印一次,当子进程10秒以后使用kill(getppid,信号)函数发送信号给父进程通过signal函数接受到信号,执行myfunc函数中的内容执行完了以后再执行父进程中的内容,10秒后子进程有通过kill发送一个信号给父进程,父进程接受到信号以后执行myfun1函数里面的内容,当内容执行完了,回到main函数中执行父进程

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void myfunc(int signum)
{
	int i=0;
	while(i<5)
	{
		printf("receive signum=%d,i=%d\n",signum,i);
		sleep(1);
		i++;
	}
	return;
}

void myfunc1(int signum)
{
	printf("receive signum=%d\n",signum);
	wait(NULL);
	return;
}

int main()
{
	pid_t pid;
	pid=fork();
	if(pid>0)
	{
		int i=0;
		signal(10,myfunc);
		signal(17,myfunc1);
		while(1)
		{
			printf("parent process things,i=%d\n",i);
			sleep(1);
			i++;
		}
	}
	if(pid==0)
	{
		sleep(10);
		kill(getppid(),10);
		sleep(10);
		exit(0);//kill(getppid(),SIG_CHLD)
	}
	return 0;
}

执行结果如下: 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值