进程间通信(IPC)

进程间通信(IPC)

进程之间无法直接通信,进程之间具有独立性,因为每个进程都有其独立的虚拟地址空间,虚拟地址空间的不同导致映射方式的不同,导致无法访问同样的物理空间所以无法直接通信;

进程间通信的本质就是为进程之间提供一块公共区域

进程间通信方式:管道、共享内存、消息队列、信号量等;

ipcs用于查看进程间通信资源,-m共享内存,-s信号量,-q消息队列;

ipcrm用于删除进程间通信资源;

管道

#include <unistd.h>

int pipe(int pipefd[2]);

原理及本质:

内核中的一块缓冲区(内核中的一块内存);

特性:

①**pipefd[0]**用于读数据,若管道中没有数据,read默认阻塞,直到读取到数据后返回;

②**pipefd[1]**用于写数据,如果管道中数据写满,write默认会阻塞,直到数据被读出后有空闲空间;

③若管道所有读端被关闭,write继续写入数据则会触发异常,退出程序

④若管道所有写端被关闭,read读取完缓冲区数据后,继续read将不再阻塞而是直接返回0

半双工通信(可以选择方向的单向通信,但是一般不会切换方向);

⑥管道中的数据传输是一种基于链接、先入先出、自带同步与互斥的字节流传输

生命周期随进程

匿名管道:

内核中的缓冲区没有标识符,只能用于具有亲缘关系的进程间通信,以创建进程时子进程复制父进程的方式来复制管道句柄来访问管道,并且不局限于父子进程之间;

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
	int filedes[2];
	char buffer[80];
	pipe(filedes);
	if(fork() > 0)
	{
		char s[] = "hello!\n";
		write(filedes[1], s, sizeof(s));
	}
	else
	{
		read(filedes[0], buffer, 80);
		printf("%s", buffer);
	}
}

命名管道:

内核中的缓冲区具有标识符,标识符是一个可见于文件系统的特殊管道文件(就算删除也只是删除了标识符,缓冲区不会立刻被释放),多个进程通过打开同一个管道文件来访问同一块内核中的缓冲区(当文件还未打开时并没有在内核中开辟缓冲区,只有进程开始打开文件时才会开辟);

命名管道打开特性:

如果管道以只读被打开,会阻塞,直到管道文件也以写的方式被打开;

如果管道以只写被打开,会阻塞,直到管道文件也以读的方式被打开;

#include<sys/stats.h>

int mkfifo(const char* pathname, mode_t mode);
//创建一个命名管道标识符
//pathname:带有路径管道标识符文件名
//mode:文件权限
//返回值有个特殊错误“EEXTST”,意思是文件已经存在,此时可以接着操作不需要退出
#include<sys/stat.h>
#include<sys/stats.h>
#include<fcntl.h>
#include<iostream>
int main(){
	if((mkfifo("./test.file",0600) == -1) && errno != EEXIST){
		perror("mkfifo failure\n");
        return 0;
	}

    int fd=open("./test.file",O_RDONLY);
    if(fd<0){
        perror("open error");
        return -1;
    }
    printf("open success\n");
    while(1){
        char buf[1024]={0};
        int ret=read(fd,buf,1023);
        if(ret<0){
            perror("read error");
            close(fd);
            return -1;
        }else if(ret==0){
            perror("all write closed");
            close(fd);
            return -1;
        }
        cout<<buf<<endl;
    }
    close(fd);
}
//创建管道文件后对缓存区的读写操作与文件操作基本一致

共享内存

原理及本质:

申请了一块物理内存,需要进行数据共享的进程将该块空间映射至自己的虚拟空间,然后通过自己的虚拟地址直接访问该块物理内存

特性:

①最快的进程间通信方式(覆盖式修改,因为直接通过虚拟地址访问物理内存少了数据拷贝操作);

生命周期随内核,不是立即删除,映射链接数为0自动删除;

自身不带同步互斥,多个进程对共享内存操作存在操作的安全隐患。

操作流程:

#include<sys/shm.h>

①创建或打开共享内存

int shmget(key_t key, size_t size, int shmflag);

//key:标识符;size:共享内存大小;shmflag:打开方式&权限
//成功则返回一个操作句柄(非负),失败则返回-1

②建立映射关系

void* shmat(int shmid, void* addr, int shmflag);

//shmid:shmget返回的操作句柄,表示要操作哪个共享内存
//addr:指定映射首地址,通常为NULL
//shmflag:SHM_RDONLY为只读,默认给0为可读可写
//成功则返回映射首地址,失败返回(void*)-1

③解除映射

int shmdt(void* shm_start);

//shm_start:shmat映射的首地址

④删除共享内存

int shmctl(int shmid,int cmd, struct shmid_ds* buff);

//shmid:shmget返回的操作句柄
//cmd:要对共享内存进行的操作 IPC_RMID
//buf:用于设置或者获取共享内存信息,不用则置空

消息队列

原理及本质:

本质是内核中的优先级队列,多个进程通过访问同一个内核中的消息队列,通过向队列中添加、获取结点实现数据传输;

(不常用)

特性:

①自带同步与互斥;

②生命周期随内核;

信号量

用于实现进程间的同步与互斥的技术

原理及本质:

内核中的一个计数器&pcb等待队列,针对于资源进行计数,实现同步与互斥;

同步实现:

对于资源进行计数,在资源获取之前进行P操作,产生资源之后进行V操作;

互斥实现:

将计数器初始化为1,表示资源仅有一个,在访问数据之前进行P操作,访问完毕之后进行V操作。

操作:

P操作:获取或访问资源前进行P操作,对计数器进行判断,若小于等于0则阻塞进程,并且计数器-1,若计数器大于0,则计数-1,操作正确返回;

V操作:在产生资源之后进行V操作,计数+1,唤醒一个等待中的进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值