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

avatar
作者
筋斗云
阅读量:0

一、概念

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

信号通信的框架         * 信号的发送(发送信号进程):killraisealarm         * 信号的接收(接收信号进程) : pause()sleepwhile(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和信号灯集关联的keynsems: 信号灯集中包含的信号灯数目 semflg信号灯集的访问权限 函数返回值: 成功:信号灯集ID 出错:‐1示例:
#include<stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdlib.h> int main() { 	int semID; 	semID = semget(IPC_PRIVATE,3,0755); 	if(semID == -1) 	{ 		printf("信号灯创建失败\n"); 		perror("semget:"); 		return -1; 	} 	else 	{ 		printf("信号灯创建成功,semID = %d\n",semID); 	} 	system("ipcs -s");//查看信号灯信息 	return 0; } 

运行结果:

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

功能:控制信号量,删除信号量或初始化信号量 函数参数: semid:信号灯集ID semnum: 要修改的信号灯编号 cmd :         GETVAL:获取信号灯的值         SETVAL:设置信号灯的值         IPC_RMID:从系统中删除信号灯集合 函数返回值: 成功:0 出错:‐1 示例:
#include<stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdlib.h> int main() {         int semID;         semID = semget(IPC_PRIVATE,3,0755);         if(semID == -1)         {                 printf("信号灯创建失败\n");                 perror("semget:");                 return -1;         }         else         {                 printf("信号灯创建成功,semID = %d\n",semID);         }         system("ipcs -s");//查看信号灯信息          semctl(semID,1,IPC_RMID,NULL);         printf("删除过后的信号灯\n");         system("ipcs -s");          return 0; } ~      

运行结果:

三、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示例:
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <unistd.h>  #define SEM_READ 0 #define SEM_WRITE 0 union semun {         int val; };   void pfuntion(int id,int index) {         struct sembuf sem;         sem.sem_num = index;         sem.sem_op = -1;         sem.sem_flg = 0;          semop(id,&sem,1); }   void vfuntion(int id,int index) {         struct sembuf sem;         sem.sem_num = index;         sem.sem_op = 1;         sem.sem_flg = 0;          semop(id,&sem,1); }  int main()  {         key_t key;         pid_t pid;         int shmid,semid;         char *shmaddr;         key = ftok("a.c",1);         semid = semget(key,2,IPC_CREAT|0755);//创建信号灯         if(semid == -1)         {                 perror("semget");                 return -1;         }          shmid = shmget(key,128,IPC_CREAT|0755);//创建共享内存         if(shmid == -1)         {                 perror("shmget");                 return -2;         }         //初始化信号灯         union semun mynu;         //初始化读         mynu.val = 0;//读的信号灯值         semctl(semid,SEM_READ,SETVAL,mynu);          //初始化写         mynu.val = 1;//写的信号灯值         semctl(semid,SEM_WRITE,SETVAL,mynu);          pid = fork();         if(pid == -1)         {                 perror("fork");                 return -3;         }        if(pid > 0)         {                 printf("这是一个父进程\n");                 while(1)                 {                         shmaddr = (char *)shmat(shmid,NULL,0);                         pfuntion(semid,SEM_READ);                         printf("父进程请输入数据:");                         fgets(shmaddr,32,stdin);                         vfuntion(semid,SEM_WRITE);                 }         }          if(pid == 0)         {                 printf("这是一个子进程\n");                 while(1)                 {                         shmaddr = (char *)shmat(shmid,NULL,0);                         pfuntion(semid,SEM_READ);                         printf("子进程读取到的数据是:%s\n",shmaddr);                         vfuntion(semid,SEM_WRITE);                  }         }         return 0; }                                             

运行结果:

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!