答:因为进程是具有独立性的原因是每个进程都操控自己的虚拟地址空间,无法访问其他进程的地址空间,为了让进程间可以传输数据,提供进程间通信方式,本质上就是提供了一个可以让进程间通信的介质(类似人们之间可以通过手机进行通信)
在内核空间创建了一个有大小限制的、具有同步和互斥性质的缓冲区
管道有以下两种类型
因为创建的管道只能在进程内(通过管道接口)获得管道的操作句柄(在文件系统没有可见的标识符),而子进程可以通过拷贝父进程的方法获得操作句柄,因此只能在具有亲缘关系的进程间进行通信,所以称为匿名管道。
int pipe(int fildes[2]);
fildes:用来保存管道的操作句柄,是一个输出型参数,遵循一切皆文件的原则:对管道的操作和对文件的操作相同,区别在于其中fildes[0]是专门用来读管道的文件描述符,fildes[1]是专门用来向管道写数据的文件描述符。
返回值:成功创建管道返回0,失败返回-1。
创建子进程每隔1s向管道写入数据,父进程一直读取数据。
//本demo用来演示管道的应用实现和读写测试
#include
#include
#include
#include
int main()
{
int fildes[2];
int ret = pipe(fildes);
if(ret<0)
{
perror("pipe create error\n");
return -1;
}
int pid = fork();
if(pid < 0)
{
perror("fork error\n");
return -1;
}
if(pid == 0)
{
close(fildes[1]);//使用匿名管道时,哪一端不用就关闭它。
while(1)
{
char buf[1024];
read(fildes[0],buf,1024);
printf("%s\n",buf);
}
}
else
{
close(fildes[0]);//使用匿名管道时,哪一端不用就关闭它。
int i=0;
char buf[1024];
while(1)
{
sleep(1);
sprintf(buf,"这是第%d条数据\n",i++);
write(fildes[1],buf,strlen(buf));
printf("%s\n",buf);
}
}
waitpid(pid,NULL,0);
return 0;
}
命名管道和匿名管道的区别是,他会生成一个在文件系统可见的管道文件,存储在磁盘上。这样不同进程都可以通过这个管道文件找到对应的在内核中的管道。
对命名管道的操作就像是使用文件进行通信一样,但是他底层还是使用内存的,速度比使用文件快得多。(因为使用文件操作会进行内存和磁盘之间的数据拷贝)
一个进程用来读取数据,一个进程负责写数据,当只打开一个进程时,会阻塞,直到另一个进程也打开。第一个用来读,第二个用来写。
#include
#include
#include
#include
#include
#include
#include
//int mkfifo(const char *pathname, mode_t mode);
//pathname:管道文件路径名称,mode:管道文件的操作权限
//成功返回0,失败返回-1
//这个demo用来演示命名管道的基本操作
int main()
{
char *file = "./test.fifo";
int ret=mkfifo(file,0664);
if(ret<0){
if(errno!=EEXIST){//说明fifo文件存在存在
perror("mkfifo error");
return -1;
}
}
int fd = open(file,O_RDONLY);
if(fd<0){
perror("open error");
return -1;
}
printf("open sucess\n");
char buf[1024];
while(1)
{
sleep(1);
read(fd,buf,1023);
printf("%s\n",buf);
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
int main()
{
char *file = "./test.fifo";
int ret=mkfifo(file,0664);
if(ret<0){
if(errno!=EEXIST){
perror("mkfifo error");
return -1;
}
}
int fd = open(file,O_WRONLY);
if(fd<0){
perror("open error");
return -1;
}
printf("write open sucess\n");
char buf[1024];
int i=0;
while(1)
{
sprintf(buf,"我是第%d条数据\n",i++);
write(fd,buf,strlen(buf));
}
return 0;
}
用于进程间的数据共享——最快的进程通信方式
为什么说是最快的进程间通信方式?
共享内存使用步骤:
通过一个例子学习使用共享内存:
#include
#include
#include
#include
#include
#include
#include
#include
//int shmget(key_t key, size_t size, int shmflg);
//这个demo用来演示shmget的使用
#define IPC_KEY 0x12345678//设置共享内存标识
#define SHM_SIZE 4096//设置共享内存大小
int main()
{
int shmid = shmget(IPC_KEY,SHM_SIZE,IPC_CREAT|0664);
//0664设置共享内存权限
if(shmid<0){
perror("shmget error");;
return -1;
}
//建立映射关系,第二个参时是设置共享内存映射首地址,但是我们一般设置为NULL,让操作系统设置一个合适的位置。
//第三个参数是设置进程权限,设置SHM_RDONLY的前提是该文件必须要有可读权限。设置其他表示可读可写。
//返回值:成功返回映射的首地址,失败返回(void*)-1
void *shm_start = shmat(shmid,NULL,0);
if(shm_start==(void *)-1){
perror("shmat error");
return -1;
}
int pid=fork();
if(pid<0)
{
perror("fork error\n");
return -1;
}
if(pid==0)
{
while(1)
{
shmat(shmid,NULL,0);
printf("%s\n",shm_start);
sleep(2);
}
}
else
{
int i=0;
while(1){
sprintf((char*)shm_start,"我是第%d条数据",i++);
sleep(1);
}
}
//关闭映射关系,参数是映射首地址
shmdt(shm_start);
//关闭共享内存,第二个参数设置对共享内存的操作
//第三个参数获取共享内存的一些属性
shmctl(shmid,IPC_RMID,NULL);
waitpid(pid,NULL,0);
return 0;
}
共享内存的特征: