前言
今天我们讨论进程之间的通信,利用管道(pipe)和共享内存(share memory)实现数据流通。
1.管道(pipe)
管道是最古老也是最容易理解的通信方式,它有两个限制
- 一个管道只能在一个方向上传送数据
- 管道只能在拥有共同父进程(指同一个登录shell)的进程间使用
也就是说在开始于一个登录shell以及由该shell派生出来的所有进程中可以运用管道通信。如图
#include<unistd.h>
int pipe(int filedes[2]);//创建成功返回0,失败返回-1,filedes[0]为读,filedes[1]为写,其内容为文件描述符
下面给出管道通信实例代码
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
int fd[2];
pid_t pid;
char buf[64]="asdasdasdasdasd";
char buf2[64];
if(0!=pipe(fd))
perror("fail to create pipe"); //创建管道失败
pid=fork();//派生进程
if(pid<0)//派生进程失败
{perror("fail to create process");}
else if(pid>0)//父进程
{
close(fd[0]);//关闭管道的读
write(fd[1],buf,strlen(buf));//向管道写字符串
close(fd[1]);//关闭管道的写
}
else//子进程
{
close(fd[1]);//关闭管道的写
read(fd[0],buf2,64);//从管道读出字符串
puts(buf2);
close(fd[0]);//关闭管道的读
}
}
最后运行结果如图
2.共享内存
共享内存是在内存空间中开辟一段空间,供不同的进程访问。与管道相比,能在多个不同进程间共享,也不受上述管道的两种限制。可以同时对一段内存进行读与写。而且可以传输更大的数据。示意图如下
共享内存有关函数如下
1.shmget()创建共享内存
#include<sys/ipc.h>
#include<sys/shm.h>
int shmget(key_t key,size_t size,int shmflg)
若成功申请返回值为共享内存的ID,申请失败则为-1。
shmget()向OS申请一段共享内存,其中key是系统唯一的关键字可以用ftok()生成,也可以自定义,但一定得是唯一存在。size是需要多大的共享内存字节数,shmflg是操作方式。
shmflg取值意义如下
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
SHM_R 共享内存可读
SHM_W共享内存可写
2.void *shmat( ) 获得一个共享内存ID对应的内存起始地址。
#include<sys/ipc.h>
#include<sys/shm.h>
void *shmat(int shmid,const void* shmaddr,int shmflg)
若成功获得地址则返回值是地址,反之则为(void *)-1
参数shmid 是共享内存的ID,shmaddr参数指定了共享内存的地址,若为0,表示需要系统决定共享内存地址。shmflg见上。
3.int shmdt()从程序中分离一块共享内存
#include<sys/ipc.h>
#include<sys/shm.h>
int shmdt(const void * shmaddr)
函数作用:将shmaddr所指向的共享内存从程序中分离出来,不再随着程序的终止而被抹去。
实例代码见下
//write.c-->gcc write.c -o write
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
void main()
{
int shmid;
char *ptr;
char *str="qweqweqweqweqwe";
shmid=shmget(0x2f,1024,SHM_W|SHM_R|IPC_CREAT|IPC_EXCL);
if(-1==shmid)
perror("fail to create share memory");
ptr=(char *)shmat(shmid,0,0);
if((void *)-1==ptr)
perror("fail to get share memory");
strcpy(ptr,str);
shmdt(ptr);
}
//read.c-->gcc read.c -o read
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
void main()
{
int shmid;
char *ptr;
shmid=shmget(0x2f,1024,SHM_W|SHM_R|IPC_EXCL);
if(-1==shmid)
perror("fail to create share memory");
ptr=(char *)shmat(shmid,0,0);
if((void *)-1==ptr)
perror("fail to get share memory");
puts(ptr);
shmdt(ptr);
}
运行结果如下
但是当我们再一次执行write程序时会发生报错。其错误原因就是内存中已经有了0x2f这个key值,而我们实例中没有删除共享内存。使用命令ipcs查看目前共享资源。
使用命令ipcrm释放指定的共享内存
再次执行实例再不报错
写在最后
今天我们对进程间的通信进行了一定的挖掘,对进程间数据的共享掌握了一些方法。下次我们将讨论通信机制主角——信号