进程IPC 的 7种方式

linux下 进程通讯IPC的方式主要有以下7种:
1.文件
2.共享内存
3.信号
4.管道
5.套接字
6.消息列队
7.信号量
 
以下正文 中 一一 分析下:

1.文件 ,记得 加文件锁 lockf.使用少,略去

2.共享内存

    由于内存的保护机制的作用,进程不会简单地将自己的内存空间暴露给其他进程,并允许这些进程 进行读写,根据linux下的内存保护机制,进程中的一个指针指向的内存地址 是 一个虚拟地址,所以不会涉及到真实的物理地址,传递这个地址 到其他进程并不能达到 我们期望的结果。总之,一个虚拟地址,仅仅在创建它的那个进程中有意义。
    任何要被共享的内存都必须经过 显示的分配,而不是简单的 在堆上分配,
 

POSIX 共享内存的api:

函数     作用    
shm_open     创建一个新的共享区域或者附加在已有的共享区域上,区域被其名字标识,函数返回各文件的描述符,类似于open系统调用    
shm_unlink     对 shm_open 返回的文件描述符 共享区域进行释放,类似于使用 unlink系统调用 对文件进行操作,知道所有的进程都不再饮用该内存后才对其进行释放。    
mmap     用于将一个文件 映射到 某一个内存区中,其中 也使用来shm_open返回的文件描述符,函数的返回值 是指向文件映射到内存地址的指针。mmap同样可以 使用纯文本文件 和一些 驱动程序的文件描述符
munmap     用于释放mmap所映射的内存区域
msync 同步存取一个映射区域 并将高速缓存的数据 回写到物理内存中,以便其他进程可以舰艇这些改变

例子 程序:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/file.h>
#include<sys/mman.h>
#include<sys/wait.h>
void error_out(constchar* msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc,char*argv[])
{
int r;
constchar*memname ="/mymen";
constsize_t region_size = sysconf(_SC_PAGE_SIZE);
//create the share memory region
int fd = shm_open(memname,O_CREAT | O_TRUNC | O_RDWR,);
if(fd ==-)
error_out("shm_open");
//allocate some memory in the region ,
r = ftruncate(fd,region_size);
if(r !=)
error_out("ftruncate");
//map the region into the memory
void*ptr = mmap(,region_size,PROT_READ | PROT_WRITE ,MAP_SHARED,fd,);
if(ptr == MAP_FAILED)
error_out("mmap");
//useness after mmap called
close(fd);
pid_t pid = fork();
//child
if(pid ==)
{
u_long *d =(u_long*)ptr;
*d =0xfdefdddd;
exit();
}
//parent
else{
int status;
waitpid(pid,&status,);
printf("child wrote %#1x\n",*(u_long*)ptr);
}
//release memory
//umap
r = munmap(ptr,region_size);
if(r !=)
error_out("munmap");
r = shm_unlink(memname);
if(r !=)
error_out("shm_ulink");
return0;
}
gcc -o posix_shm posix_shm.c -lrt
-lrt 不可缺少
 

System V 共享内存的api

 
函数     作用    
shmget     创建一个新的共享区域或者已有的共享区域上(同shm_open    +一个内存申请函数)
shmat     用于将一个文件 映射到内存区域中(同mmap)
shmdt     用于释放所映射的内存区域(同munmap
    )
shmct 对用多个用户,断开其对共享区域的连接(同shm_unlink)

例子 ,同上 ,功能完全一样:

说明:shmget函数 创建并分配了共享内存 区域,所以不需要 截断ftruncate 文件描述符的 步骤
总体而言,system V的api更得我心啊!
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/ipc.h>
#include<sys/shm.h>
#include<sys/wait.h>
void error_out(constchar* msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc,char*argv[])
{
int r;
key_t mykey =;
constsize_t region_size = sysconf(_SC_PAGE_SIZE);
//create the shared memory region
int shmid = shmget(mykey,region_size,IPC_CREAT |);
if(shmid ==-)
error_out("shmget");
//map the region into memory
void*ptr = shmat(shmid,NULL,);
if(ptr ==(void*)-)
error_out("shmat");
//useness after mmap called
pid_t pid = fork();
//child
if(pid ==)
{
u_long *d =(u_long*)ptr;
*d =0xfdefdddd;
exit();
}
//parent
else{
int status;
waitpid(pid,&status,);
printf("child wrote %#1x\n",*(u_long*)ptr);
}
//release memory
//umap
r = shmdt(ptr);
if(r ==-)
error_out("shmdt");
//remove the shared memory region
r = shmctl(shmid,IPC_RMID,NULL);
if(r ==-)
error_out("shmctl");
return0;
}
gcc -o sysv_shm sysv_shm.c
 

3.信号

    可以使用,但是 很复杂,且容易出错,略去

4.管道

        未命名管道(unnamed pipe)用于父子进程之间,
        命名管道 (fifo),用于一个计算机上平行的进程之间
api说明:
    系统调用int pipe(int filedes[2]) ; 
    返回一对 文件描述符
 
第一个文件描述符fd[0] 的作用 表示只读,第二个fd[1]表示 只写,
mkfifo(char const *pathname,mode_t mode)用于创建一个 有名管道
 

5.套接字

网络 编程 另讲
 

6.消息列队

同样有两套实现,posix和system V
都采用 固定大小、基于优先级的消息,接受者必须确定消息的大小,并一次对消息进行读取,否则读取失败,而且要确保所用的进程遵循进程相同的消息结构

system V api:

函数 作用
int msgget(key_t key,int msgflg); 创建或者附加一个消息列队,返回一个msgID
int msgctl(int msgid,int cmd,struct msgid_ds *buf) 可以用于删除一个msgID,当buf参数为空的情况下,删除消息列队的cmd为ipc_rmid
int msgsnd(int qid,void* msg,size_t msgsz,int msgflg) 发送()
ssize_t msgrcv(int qid,void* msg,size_t msgsz,int msgflg) 接收()
例子:

  

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<sys/file.h>
#include<sys/msg.h>
#include<sys/ipc.h>
struct message
{
longint mtype;
char mtext[];
};
void error_out(constchar* msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
//send msg
int send_msg(int qid,int mtype,constchar text[])
{
struct message msg ={
.mtype = mtype
};
strncpy(msg.mtext,text,sizeof(msg.mtext));
int r = msgsnd(qid,&msg,sizeof(msg),);
if(r ==-)
error_out("msgsnd");
return r;
}
//recv msg
int recv_msg(int qid,int mtype,struct message* msg)
{
int r = msgrcv(qid,msg,sizeof(struct message),mtype,);
switch(r)
{
casesizeof(struct message):
break;
case-:
perror("msgrcv");
break;
default:
printf("only recv %d bytes data\n",r);
break;
}
return r;
}
void producer(int mqid)
{
send_msg(mqid,,"type 1 - first");
send_msg(mqid,,"type 2 - second");
send_msg(mqid,,"type 1 - thrid");
}
void consumer(int qid)
{
struct message msg;
int r ;
int i ;
for(i =;i <;++i)
{
r = msgrcv(qid,&msg,sizeof(struct message),-,);
printf("[%s]\n",msg.mtext);
}
}
int main(int argc ,char*argv[])
{
//create a private (unname) message queue
int mqid;
mqid = msgget(IPC_PRIVATE,S_IREAD | S_IWRITE);
if(mqid ==-)
error_out("msgget");
pid_t pid = fork();
if(pid ==)
{
consumer(mqid);
exit();
}
else
{
int status;
producer(mqid);
wait(&status);
}
//remove the message queue
int r = msgctl(mqid,IPC_RMID,);
if(r)
perror("msgctl");
return0;
}
gcc -o systemV_mq systemV-mgq.c  
 ./systemV_mq                     
[type 1 - first]
[type 1 - thrid]
[type 2 - second]
 
特别指出的是,在消费者 函数中将 msgrecv可以接受的消息类型指定为 -2 了,它表明可以接受 类型为 2 ,或者优先级更低的消息,而且该数值越低,优先级越高,则越先被接受,为了 使 接受和发送的次序保持一致,需要将该值设定为0;
总之:当msgrecv的类型为非0 时,消息是按优先级高低进行接收的,
  • 正数,只接受 该类型的消息
  • 负数,只接受 小于或者等于 指定类型绝对值 的消息
 

posix api : 略去

 

7.信号量  semaphore

用于 保持 并发进程的同步,信号量 类似于 并发进程的 交通信号灯。
其本质 是 一个计数器,一种常用的用法是 为每个资源都分配一个信号量,所以,信号量计数的增量从来不会 大于1 ,注意 :是增量 或者减量 

posix api:

函数     作用    
sem_t *sem = sem_open()     创建信号量 并初始化为0
sem_post(sem    ) 信号量 +1    
sem_wait(sem    ) 信号量 -1 

system V  API

 
函数     作用    
semget 生成 信号量ID,
semop       通过不同的op,增或者 减 信号量

具体例子 可以百度下。

 
基础知识可以参考:
 
 
本文参考:《linux开发工具箱》
 
 
 
 
 
 
 
 
 
 
 
 
 
 

linux进程通信全面解析的更多相关文章

  1. Linux进程通信----匿名管道

    Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...

  2. Linux 进程通信之 ——信号和信号量总结

    如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存.       所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...

  3. Linux进程通信学习总结

    http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念   引用标识符:引用标识符是一个整数,表示每一个SYSV ...

  4. Linux进程通信的几种方式总结

    进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...

  5. linux进程通信之管道

    1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...

  6. linux 进程通信之 共享内存

    共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...

  7. linux进程通信

    e14: 进程间通信(进程之间发送/接收字符串/结构体): 传统的通信方式: 管道(有名管道 fifo,无名管道 pipe) 信号 signal System V(基于IPC的对象):         ...

  8. linux 进程通信 管道

    1. 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管 ...

  9. Linux进程通信——管道

    管道(pipe)本质上是一种文件,管道通信本质上是通过读写文件通信,但是管道解决了文件的两个问题:限制管道大小,解决read()调用文件结束问题. 管道一个环形的缓冲区,通过两个进程以生产者/消费者的 ...

随机推荐

  1. LeetCode:比较含退格字符串【844】

    LeetCode:比较含退格字符串[844] 题目描述 给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果. # 代表退格字符. 示例 1: 输入:S = ...

  2. CROS跨域 解决方案 之 tomcat 做过滤处理解决

    摘自:http://www.cnblogs.com/liuwenhao-1/articles/6963540.html 1 .在项目中常常遇到本地访问服务器上的链接数据访问不到,并出现如下问题: 这是 ...

  3. 菜单Menu

    <Menu HorizontalAlignment="> <MenuItem Header="文件"> <MenuItem Header=& ...

  4. Python 面向对象的综合应用

    # 面向对象的综合应用 # 计算器:实现一些基本的计算操作,已经打印结果 # --------------- 代码1 ---------------------- def add(x, y): ret ...

  5. js异步获取数据的问题

    最近做js开发的时候发现了很多哥们不能区分同步和异步的区别,典型的在ajax部分,在该ajax为异步操作的时候,获取不到success之后的data的值,于是产生了各种奇葩的写法.比如创建一个局部变量 ...

  6. EF Code-First 学习之旅 从已存在的数据库进行Code First

    namespace EFDemo { using System; using System.Data.Entity; using System.ComponentModel.DataAnnotatio ...

  7. C#与C++之间类型对应关系

    //C++中的DLL函数原型为  //extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, unsigned c ...

  8. 多线程-栅栏CyclicBarrier

    上一篇总结了闭锁CountDownLatch,这一篇总结一下栅栏CyclicBarrier.它们两者之间的区别主要是,闭锁是等待一个事件发生,比如上一篇的田径比赛,运动员等待裁判哨声一响就可以开始跑, ...

  9. 通过HBase API进行开发

    http://www.cnblogs.com/netbloomy/p/6683509.html 一.将HBase的jar包及hbase-site.xml添加到IDE 1.到安装HBase集群的任意一台 ...

  10. QTableWidget 列排序

    connect(uirecord.tableWidget->horizontalHeader(),SIGNAL(sectionClicked(int)),this,SLOT(record_sor ...