linux-进程间通信之我见

==================================================================================================

常用的进程间通信方式有:

1.传统的进程间通信方式

无名管道(pipe)、有名管道(fifo)、信号(signal)

2.System V IPC 对象

共享内存(share memory)、消息队列(message queue)、信号灯(semaphore)

3.BSD socket 伯克利套接字

==================================================================================================

在这里主要谈一下System V IPC 对象。谈到IPC对象就不得不说一下ftok(),用它可以产生一个key_t类型的键值;

ftok:

    原型:key_t ftok(const char *pathname, int proj_id); //来自Linux 3.2.0-29 (man ftok)

    @pathname:一个存在的路径名,理论上可以是任何一个目录或文件名,通常使用的是当前目录。

    @proj_id:是一个子序号,我们可以这样理解,假设在我们的程序中,我们需要多个相同类型的IPC对象,但是我们又不想更改pathname,那么,我们就可以很方便的通过更改子序号来产生不同的key。

    @返回值:我们需要的键值。

   用法举例     

if((key = ftok(".",'x')) < 0)
{
	perror(" fail to ftok");
	return -1;
}

   :有时候不得不遇到这种尴尬的局面:想在两个应用程序之间使用IPC对象进行通信,可是又不想让两个应用程序在同一个目录下,这时pathname为当前路径就不合适了,这样的话创建的IPC对象在很大程度上不可能是同一个。(只要key相同,IPC对象必定是同一个),这个时候我们可以选择两种方式,1.直接固定key的值;2.设一个相同的绝对路径,这时,最好是找一些系统运行必备的路径,避免因为此路径被删而导致错误。

   以下以进程间通信最高效的IPC对象 共享内存数据读写为例介绍以下System V IPC对象的使用方法及注意事项:

进程间通信一般都存在同步和互斥的问题,这里假定只有一个读写端,所以只需考虑同步问题,互斥的原理可以类比,在这里不赘述。

共享内存一般和消息配合使用:

    1.由于不确定读写进程哪个先启动,所以也就无法确定共享内存是谁创建的,因此,在读写进程里都有可能因为共享内存存在而创建失败,所以判错必须排除EEXIST。

    2.要清楚这样一个逻辑:谁先创建的共享内存,就先把自己的pid写进去,然后等待对方读完pid并把它自己的pid写进共享内存。

    3.没有创建成功的进程需要先读取pid,然后将自己的pid写进共享内存,最后发送就绪消息。


写进程代码清单:  

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           #include "mytypes.h" pid_t pid_r; void write_hander(int sign_no); int main(int argc, const char *argv[]) { key_t key; int shmid; pagdata_t *shmadd; signal(SIGUSR1,write_hander); if((key = ftok(".",'x')) < 0) { perror(" fail to ftok"); return -1; } if((shmid = shmget(key, sizeof(pagdata_t), 0666 | IPC_CREAT | IPC_EXCL)) < 0) //是否创建成功判错 { if(errno == EEXIST) //如果创建失败,并且错误号为 已经存在 { shmid = shmget(key, sizeof(pagdata_t), 0666); //打开共享内存,权限是0666 if((shmadd = (pagdata_t *)shmat(shmid, NULL, 0)) < (pagdata_t *)0) //映射判错 { perror(" fail to shmat"); return -1; } pid_r = shmadd->pid; // 读进程的pid(以消息的方式同步进程) printf(" communication pid is %d\n",pid_r); shmadd->pid = getpid(); // 将自己的pid写入共享内存 kill(pid_r, SIGUSR2); //告诉读进程写入pid就绪,可以开始读 } else //表示其他原因产生错误 { perror(" fail to shmget"); return -1; } } else { if((shmadd = (pagdata_t *)shmat(shmid, NULL, 0)) < (pagdata_t *)0) //该进程创建共享内存成功,映射判错 { perror(" fail to shmat"); return -1; } shmadd->pid = getpid(); //写入自己的pid pause(); //等待对方写入pid完毕 pid_r = shmadd->pid; //读取对方的pid printf(" communication pid is %d\n",pid_r); } while(1) //配对成功,开始交换数据 { printf(" plz input messages : "); fgets(shmadd->data, sizeof(shmadd->data)-1, stdin); kill(pid_r, SIGUSR2); if(strncmp(shmadd->data, "over", 4) == 0) { printf(" communication over\n"); exit(0); } pause(); } return 0; } void write_hander(int sign_no) { return ; } 
          
         
       
      
      
     
     
    
    
   
   

读进程代码清单
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          #include 
         
           #include 
          
            #include "mytypes.h" pid_t pid_w; void read_hander(int sign_no); int main(int argc, const char *argv[]) { key_t key; int shmid; pagdata_t *shmadd; signal(SIGUSR2, read_hander); if((key = ftok(".",'x')) < 0) { perror(" fail to ftok"); return -1; } if((shmid = shmget(key, sizeof(pagdata_t), 0666 | IPC_CREAT | IPC_EXCL)) < 0) { shmid = shmget(key, sizeof(pagdata_t), 0666); if(errno == EEXIST) { if((shmadd = (pagdata_t *)shmat(shmid, NULL, 0)) < (pagdata_t *)0) { perror(" fail to shmat"); return -1; } pid_w = shmadd->pid; shmadd->pid = getpid(); kill(pid_w, SIGUSR1); printf(" communication pid is %d\n",pid_w); } else { perror(" fail to shmget"); return -1; } } else { if((shmadd = (pagdata_t *)shmat(shmid, NULL, 0)) < (pagdata_t *)0) { perror(" fail to shmat"); return -1; } shmadd->pid = getpid(); pause(); pid_w = shmadd->pid; printf(" communication pid is %d\n",pid_w); } while(1) { pause(); if(strncmp(shmadd->data, "over", 4) == 0) { shmdt(shmadd); shmctl(shmid, IPC_RMID, NULL); printf(" communication over\n"); exit(0); } printf(" Resieved massage From %d is : %s",pid_w, shmadd->data); kill(pid_w, SIGUSR1); } return 0; } void read_hander(int sign_no) { return ; } 
           
          
        
       
       
      
      
     
     
    
    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值