博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux进程通信全面解析
阅读量:6403 次
发布时间:2019-06-23

本文共 5906 字,大约阅读时间需要 19 分钟。

 

进程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
#include
#include
#include
#include
#include
#include
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 regionint fd = shm_open(memname,O_CREAT | O_TRUNC | O_RDWR,0666);if(fd ==-1)error_out("shm_open");//allocate some memory in the region ,r = ftruncate(fd,region_size);if(r !=0)error_out("ftruncate");//map the region into the memoryvoid*ptr = mmap(0,region_size,PROT_READ | PROT_WRITE ,MAP_SHARED,fd,0);if(ptr == MAP_FAILED)error_out("mmap");//useness after mmap calledclose(fd);pid_t pid = fork();//childif(pid ==0){u_long *d =(u_long*)ptr;*d =0xfdefdddd;exit(0);}//parentelse{int status;waitpid(pid,&status,0);printf("child wrote %#1x\n",*(u_long*)ptr);}//release memory//umapr = munmap(ptr,region_size);if(r !=0)error_out("munmap");r = shm_unlink(memname);if(r !=0)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
#include
#include
#include
#include
#include
#include
void error_out(constchar* msg){perror(msg);exit(EXIT_FAILURE);}int main(int argc,char*argv[]){int r;key_t mykey =12345678;constsize_t region_size = sysconf(_SC_PAGE_SIZE);//create the shared memory regionint shmid = shmget(mykey,region_size,IPC_CREAT |0666);if(shmid ==-1)error_out("shmget");//map the region into memoryvoid*ptr = shmat(shmid,NULL,0);if(ptr ==(void*)-1)error_out("shmat");//useness after mmap calledpid_t pid = fork();//childif(pid ==0){u_long *d =(u_long*)ptr;*d =0xfdefdddd;exit(0);}//parentelse{int status;waitpid(pid,&status,0);printf("child wrote %#1x\n",*(u_long*)ptr);}//release memory//umapr = shmdt(ptr);if(r ==-1)error_out("shmdt");//remove the shared memory regionr = shmctl(shmid,IPC_RMID,NULL);if(r ==-1)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
#include
#include
#include
#include
#include
#include
#include
#include
struct message{longint mtype;char mtext[128];};void error_out(constchar* msg){perror(msg);exit(EXIT_FAILURE);}//send msgint 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),0);if(r ==-1)error_out("msgsnd");return r;}//recv msgint recv_msg(int qid,int mtype,struct message* msg){int r = msgrcv(qid,msg,sizeof(struct message),mtype,0);switch(r){casesizeof(struct message):break;case-1:perror("msgrcv");break;default:printf("only recv %d bytes data\n",r);break;}return r;}void producer(int mqid){send_msg(mqid,1,"type 1 - first");send_msg(mqid,2,"type 2 - second");send_msg(mqid,1,"type 1 - thrid");}void consumer(int qid){struct message msg;int r ;int i ;for(i =0;i <3;++i){r = msgrcv(qid,&msg,sizeof(struct message),-2,0);printf("[%s]\n",msg.mtext);}}int main(int argc ,char*argv[]){//create a private (unname) message queueint mqid;mqid = msgget(IPC_PRIVATE,S_IREAD | S_IWRITE);if(mqid ==-1)error_out("msgget");pid_t pid = fork();if(pid ==0){consumer(mqid);exit(0);}else{int status;producer(mqid);wait(&status);}//remove the message queueint r = msgctl(mqid,IPC_RMID,0);if(r)perror("msgctl");return0;}

 

gcc -o systemV_mq systemV-mgq.c  
 ./systemV_mq                     
[type 1 - first]
[type 1 - thrid]
[type 2 - second]
 
特别指出的是,在消费者 函数中将 
msg
recv可以接受的消息类型指定为 -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开发工具箱》
 
 
 
 
 
 
 
 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/Stultz-Lee/p/6709490.html

你可能感兴趣的文章
c++设计一个无法被继承的类
查看>>
Scrum为什么不喜欢“来自客户的频繁变更”?
查看>>
[浪子学编程][读书笔记]-道法自然之设计方法
查看>>
Silverlight button 图片切换样式
查看>>
Windows Azure Virtual Machine (1) IaaS用户手册
查看>>
python 提取主域名和子域名代码——先根据规则提取,如果有问题,则使用tldextract...
查看>>
漂亮的后台 模板
查看>>
数据挖掘学习08 - 实验:使用R评估kmeans聚类的最优K
查看>>
git配置
查看>>
灵活定义神经网络结构
查看>>
java10 WeakHashMap
查看>>
CentOS7下安装mysql5.6修改字符集为utf8并开放端口允许远程访问
查看>>
ElasticSearch入门 第二篇:集群配置
查看>>
Solr开发文档
查看>>
关于Python Package下的Module import方式[转]
查看>>
对于key的操作命令
查看>>
MySQL · 捉虫动态 · 字符集相关变量介绍及binlog中字符集相关缺陷分析
查看>>
.Net Discovery系列之十一-深入理解平台机制与性能影响 (中)
查看>>
在Visual Studio引用对话框中找不到Civil 3D 2011 64位的COM组件的解决办法
查看>>
JS组件系列——自己动手扩展BootstrapTable的 冻结列 功能:彻底解决高度问题
查看>>