LINUX进程间的通信(IPC)--信号

一、概念

信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。信号已经是存在内核中的了,不需要用户自己创建。

信号通信的框架
        * 信号的发送(发送信号进程):kill raise alarm
        * 信号的接收(接收信号进程) : pause() sleep while(1)
        * 信号的处理(接收信号进程) :signal

二、相关函数

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

所需头文件:
#include<signal.h>
#include<sys/types.h>
函数原型: int kill(pid_t pid, int sig);
参数:
函数传入值: pid
        正数:要接收信号的进程的进程号
        0:信号被发送到所有和 pid 进程在同一个进程组的进程
        ‐1:信号发给所有的进程表中的进程 ( 除了进程号最大的进程外 )
sig :信号
函数返回值:成功 0 出错 ‐1
示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>


int main(int argc,char *argv[])
{
        int pid,sig;
        if(argc != 3)
        {
                printf("输入错误\n");
                return -1;
        }
        sig = atoi(argv[1]);
        pid = atoi(argv[2]);

        printf("pid = %d,sig = %d\n",pid,sig);

        int rnt = kill(pid,sig);
        if(rnt == 0)
        {
                printf("杀死进程%d成功\n",pid);
        }

        return 0;
}
~   
运行结果:

2.raise: 发信号给自己 == kill(getpid(), sig)

所需头文件:
#include<signal.h>
#include<sys/types.h>
函数原型: int raise(int sig);
参数:
函数传入值: sig :信号
函数返回值:
成功 0 出错 ‐1
示例:
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
        printf("hello;\n");


        //int rnt = raise(9);
        int rnt = kill(getpid(),9);
        if(rnt == 0)
        {
                printf("杀死自己成功\n");
        }

        printf("world\n");
        return 0;
}

运行结果:

3.alarm : 发送闹钟信号的函数

alarm raise 函数的比较:
        相同点:让内核发送信号给当前进程
        不同点:
                alarm 只会发送SIGALARM 信号
                alarm 会让内核定时一段时间之后发送信号, raise 会让内核立刻发信号
所需头文件 #include <unistd.h>
函数原型 unsigned int alarm(unsigned int seconds)
参数:
seconds :指定秒数
返回值:
        成功:如果调用此alarm() 前,进程中已经设置了闹钟时间,则 返回上一个闹钟时间的剩余时间,否则返回 0
        出错:‐1
示例:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int main()
{
	int i;
	alarm(5);
	printf("alarm start\n");
	for(i =0 ;i<20;i++)
	{
		sleep(1);
		printf("i = %d\n",i);
	}

	return 0;
}

运行结果:

4.信号的接收

接收信号的进程,要有什么条件:要想使接收的进程能收到信号,这个进程不能结束 : sleep        
pause:进程状态为 S (休眠)
函数原型 int pause(void);
函数返回值:
成功: 0 ,出错: ‐1
示例:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int main()
{
        int i,rnt;
        printf("pause start\n");
        pause();
        for(i =0 ;i<20;i++)
        {
                sleep(1);
                printf("i = %d\n",i);
        }
        return 0;
}

运行结果:

5.信号的处理

收到信号的进程,应该怎样处理? 处理的方式:
        1.进程的默认处理方式(内核为用户进程设置的默认处理方式)
                A:忽略B :终止进程 C: 暂停
        2.自己的处理方式:
                自己处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的的处理方式、
函数原型 void (*signal(int signum, void (*handler)(int)))(int);
参数:
signum 指定信号
handler:
        1.SIG_IGN:忽略该信号。
        2.SIG_DFL:采用系统默认方式处理信号
        3.自定义的信号处理函数指针
函数返回值
成功:设置之前的信号处理方式
出错: ‐1
signal 函数有二个参数,第一个参数是一个整形变量(信号值),第二个参数是一个函数指针,是我们自己写的处理函
数;这个函数的返回值是一个函数指针。

1.示例:自定义的信号处理函数指针

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void myfun(int signum)
{
        int i;
        while(i<5)
        {
                printf("signum = %d,i = %d\n",signum,i);
                i++;
                sleep(1);
        }
}
int main()
{
        int i,rnt;
        signal(14,myfun);//14信号是定时器到时发出
        printf("alarm start\n");
        alarm(7);
        for(i =0 ;i<10;i++)
        {
                sleep(1);
                printf("i = %d\n",i);
        }
        return 0;
}

运行结果:
PS:回调函数执行完之后会重新回到主函数继续执行

2.示例:忽略该信号

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void myfun(int signum)
{
	int i;
	while(i<5)
	{
		printf("signum = %d,i = %d\n",signum,i);
		i++;
		sleep(1);
	}
}
int main()
{
	int i,rnt;
	signal(14,myfun);//14信号是定时器到时发出
	printf("alarm start\n");
	alarm(7);

	signal(14,SIG_IGN);
	for(i =0 ;i<10;i++)
	{
		sleep(1);
		printf("i = %d\n",i);
	}
	return 0;
}

运行结果:

3.示例:采用系统默认方式处理信号

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void myfun(int signum)
{
	int i;
	while(i<5)
	{
		printf("signum = %d,i = %d\n",signum,i);
		i++;
		sleep(1);
	}
}
int main()
{
	int i,rnt;
	signal(14,SIG_DFL);
	printf("alarm start\n");
	alarm(7);
	for(i =0 ;i<10;i++)
	{
		sleep(1);
		printf("i = %d\n",i);
	}
	return 0;
}

运行结果:

三、信号灯

信号灯集合(可以包含多个信号灯) IPC 对象是一个信号的集合(多个信号量) 一个信号灯有多个信号量。

1.相关函数

1.函数原型: int semget(key_t key, int nsems, int semflg);

功能:创建一个新的信号量或获取一个已经存在的信号量的键值。
函数参数:
key 和信号灯集关联的 key
nsems: 信号灯集中包含的信号灯数目
semflg 信号灯集的访问权限
函数返回值:
成功:信号灯集 ID
出错: ‐1

2.函数原型:int semctl ( int semid, int semnum, int cmd…union semun arg(不是地址));

功能:控制信号量,删除信号量或初始化信号量
函数参数:
semid :信号灯集 ID
semnum: 要修改的信号灯编号
cmd :
        GETVAL:获取信号灯的值
        SETVAL:设置信号灯的值
        IPC_RMID:从系统中删除信号灯集合
函数返回值:
成功: 0
出错: ‐1

三、PV操作

int semop(int semid ,struct sembuf *sops ,size_t nsops);
功能:用户改变信号量的值。也就是使用资源还是释放资源使用权
参数:
semid : 信号量的标识码。也就是 semget ()的返回值
sops 是一个指向结构体数组的指针。
        struct sembuf{
        unsigned short sem_num;   // 信号灯编号;
        short sem_op;                        //对该信号量的操作。‐1 ,P 操作, 1 V 操作
        short sem_flg;                        //0阻塞,1非阻塞
        };
sem_op : 操作信号灯的个数
// 如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果 sem_op 的值为负 数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op 的绝对值。通常用于获取资源的使用 权;如果sem_op 的值为 0 ,则操作将暂时阻塞,直到信号的值变为 0
  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值