进程间通信--管道通信和共享内存

进程间通信的目的:

数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变

通信的本质:

1、操作系统需要直接或者间接的给通信双方提供一份公共资源,通过这公共资源来进行数据的传输。
2、不同通信的种类本质就是,公共资源属于哪一个模块。例如:文件系统提供--管道通信、一块内存--共享内存方式、如果是一个队列---消息队列、如果是计数器---信号量等等。

匿名管道pipe

创建方式:在内核中开辟一块缓冲区,这块缓冲区没有具体的标识符,因此只能用于具有亲缘关系的进程间通信,子进程可以通过复制父进程的fd,从而可以和父进程一起访问所开辟的管道。匿名管道不需要从磁盘中加载一个文件到内存中,操作系统可以直接创建一个内存级文件以供使用。

相关函数:

#include <unistd.h>
功能:创建一无名管道 原型 int pipe(int fd[2]);
参数:
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端 返回值:成功返回0,失败返回错误代码

#include <unistd.h>
int pipe(int pipefd[2]);
​
int mian()
{
    int fds[2];     //fds[0]保存的是读端的fd, fds[1]保存的是写端的fd
    int n = pipe(fds);
    assert(n == 0); //pipe调用成功返回0
    return 0;
}

读写规则:

1、读慢写快:缓冲区写满之前会根据读端的速度进行读,写端也按照自己的速度进行写入。 当缓冲区被写满了之后,写端会等待读端读取数据之后再进行写入,目的是防止内容被覆盖。

2、读快写慢:读端会等待写端写入数据之后再进行读取。

3、写端关闭:可以根据读取数据的函数返回值来判断对方是否关闭,然后进行相关操作。

4、读端关闭:此时写端会毫无意义,操作系统会给进程发送13号(SIGPIPE)信号,终止写端。

管道的特征:

1、管道的生命周期随进程

2、管道可以用来具有血缘关系的进程之间进行通信,常用于父子进程之间的通信。

3、管道是面向字节流的

4、半双工通信---单向通信(特殊的概念)

5、具有互斥与同步机制

命名管道

创建方式:通过函数或者命令创建一个命名管道文件,让不同的进程打开指定名称(路径 + 文件名)的同一份文件,而路径加文件名具有唯一性。我们不需要使用它对应的磁盘空间(不需要将对应的数据刷新进磁盘),只需要它的唯一性。匿名管道其实也是通过唯一性来标定的,匿名管道虽然没有名字,但是因为开辟空间获得了一个地址,而地址具有唯一性。

函数创建:

int main(int argc, char *argv[])
{
    mkfifo("p2", 0644);
    return 0;
}

命令创建:makefifo + filename

命令删除:rm + filename

函数删除管道文件:

#include <unistd.h>
int unlink(const char *pathname);
通信方式:两个不同的进程,一个进程用读的方式打开该管道文件,另外一个进程用写的方式打开文件。就可以通过struct_file{}中的缓冲区进行通信了。

共享内存:

概念:通过让不同的进程看到同一个内存快的方式,叫做共享内存。

基本原理:

1、申请一块空间----共享内存
2、将进程和共享内存进行映射---挂接
3、用完之后取消关联---去关联
4、释放共享内存

说明:
1、这个地方申请的空间和malloc有点相似,但是完全不一样,这是专门为了通信设置的一种方式。
2、共享内存是一种通信的方式,所有想通信的进程都可以自己创建共享内存来进行使用。
3、系统中可能同时存在很多的共享内存。

相关函数:

函数:int shmget(key_t key, size_t size, int shmflg);
功能:申请一块自定义大小的共享内存
参数列表:
key:进行唯一性标识 size:所申请空间的大小
shmflg:选项如下,可以 | 上多个
IPC_CREAT:创建的内存不存在就创建,存在的话就获取
IPC_EXCL:无法单独是使用,IPC_CREAT | IPC_EXCL :意思是不存在就创建,存在就返回错误

函数:key_t ftok(const char *pathname, int proj_id)
功能:返回 shmget函数所需要的key值
参数列表:
pathname:文件路径名
proj_id:随意设置,Unix上面范围是0~255

函数: void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:将进程和对应共享内存进行挂接
参数列表:
shmid:申请内存函数的返回值
shmaddr:指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址
shmflg:是一组标志位,通常为0

函数:int shmdt(const void *shmaddr)
功能:与共享内存去关联
参数列表:
shmaddr:对应调用shmat的返回值

函数:int shmctl(int shmid, int cmd, struct shmid_ds *buf)
功能:控制共享内存块
参数列表:
shmid:共享内存表示符
cmd:IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存 buf:给用户可以获得的内容如下

struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Last change time */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...
           };

生命周期:随OS!

删除命令:

特点:所有进程间通信之间速度最快的,因为是通过页表直接映射物理内存,可以减少数据拷贝的次数。

读写规则:不给我们进行同步和互斥的操作,没有对数据做任何的保护

管道VS共享内存

猜你喜欢

转载自blog.csdn.net/weixin_58250064/article/details/129433458
今日推荐