Linux has an in-depth understanding of multi-process communication

1. Inter-process communication

1.1 Purpose of inter-process communication

  • Data transfer : One process needs to send its data to another process
  • Resource sharing : sharing the same resources between multiple processes.
  • Notification event : A process needs to send a message to another process or a group of processes to notify it (them) that a certain event has occurred (such as notifying the parent process when the process terminates).
  • Process control : Some processes hope to completely control the execution of another process (such as the Debug process). At this time, the control process hopes to intercept all traps and exceptions of another process and be able to know its status changes in time. 
数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止
时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另
一个进程的所有陷入和异常,并能够及时知道它的状态改变。

1.2 Development of inter-process communication 

  • pipeline
  • System V interprocess communication
  • POSIX inter-process communication

1.3 Classification of inter-process communication

1.3.1 Pipeline

  • anonymous pipe
  • named pipe

1.3.2 System V IPC

  • System V message queue
  • System V shared memory
  • System V semaphore

1.3.3 POSIX IPC

  • message queue
  • Shared memory
  • Signal amount
  • mutex
  • condition variable
  • read-write lock

2. Pipeline (related)

Pipes are the oldest form of inter-process communication in Unix.

We call a data flow from one process to another process a "pipeline"

2.1 Use fork to share pipeline principles

2.2 Anonymous pipe 

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

Example code 

打开管道
获取键盘stdin的数据读到buf中
把buf中的数据写到管道中
从管道中把数据写到回buf中
再把buf中的数据写到stdout中

2.3 From the perspective of file descriptors - in-depth understanding of pipelines

2.4 From the kernel perspective - the essence of pipelines 

So, treat pipes like files! The use of pipes is consistent with files, which caters to the "Linux everything is a file idea". 

Add the implementation of the pipeline in my_shell:

添加功能

2.5 Pipeline reading and writing rules

当没有数据可读时
O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
当管道满的时候
O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
如果所有管道写端对应的文件描述符被关闭,则read返回0
如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程
退出
当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

2.6 Pipeline Characteristics

In Linux, if the file descriptor of an anonymous pipe is closed, it cannot be opened again, so only one-way communication can be achieved.

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创
建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
管道提供流式服务
一般而言,进程退出,管道释放,所以管道的生命周期随进程
一般而言,内核会对管道操作进行同步与互斥
管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

3. Named pipes

  • One limitation of pipe applications is that they can only communicate between processes that have a common ancestor (related to each other).
  • If we want to exchange data between unrelated processes, we can use FIFO files to do the job, which are often called named pipes.
  • A named pipe is a special type of file

3.1 Create a named pipe

Create using command line

mkfifo filename

Create in code

int mkfifo(const char *filename,mode_t mode);

Real permissions are affected by umask

The difference between anonymous pipes and named pipes

匿名管道由pipe函数创建并打开。
命名管道由mkfifo函数创建,打开用open
FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完
成之后,它们具有相同的语义。

Named pipe opening rules

如果当前打开操作是为读而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
O_NONBLOCK enable:立刻返回成功
如果当前打开操作是为写而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

Experiment 1-File copying using named pipes

Experiment 2-Use named pipes to implement server&client communication

3. system V shared memory

Shared memory areas are the fastest form of IPC. Once such memory is mapped into the address space of the process that shares it, these inter-process data transfers no longer involve the kernel. In other words, processes no longer transfer data to each other by executing system calls into the kernel.

Shared memory data structure

struct shmid_ds {
 struct ipc_perm shm_perm; /* operation perms */
 int shm_segsz; /* size of segment (bytes) */
 __kernel_time_t shm_atime; /* last attach time */
 __kernel_time_t shm_dtime; /* last detach time */
 __kernel_time_t shm_ctime; /* last change time */
 __kernel_ipc_pid_t shm_cpid; /* pid of creator */
 __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
 unsigned short shm_nattch; /* no. of current attaches */
 unsigned short shm_unused; /* compatibility */
 void *shm_unused2; /* ditto - used by DIPC */
 void *shm_unused3; /* unused */
};

 

Shared memory functions

shmget function

功能:用来创建共享内存
原型
 int shmget(key_t key, size_t size, int shmflg);
参数
 key:这个共享内存段名字
 size:共享内存大小
 shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

shmat function

功能:将共享内存段连接到进程地址空间
原型
 void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
 shmid: 共享内存标识
 shmaddr:指定连接的地址
 shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - 
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

shmdt function

功能:将共享内存段与当前进程脱离
原型
 int shmdt(const void *shmaddr);
参数
 shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

shmctl function

功能:用于控制共享内存
原型
 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
 shmid:由shmget返回的共享内存标识码
 cmd:将要采取的动作(有三个可取值)
 buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

cmd

IPC_STAT: Get the status of the shared memory and copy the shmid_ds structure of the shared memory to buf

IPC_SET: Change the status of the shared memory and copy the uid, gid, and mode in the shmid_ds structure pointed to by buf to the shmid_ds structure of the shared memory.

IPC_RMID: Delete this shared memory

 

  • The key is the key of the shared memory;
  • shmid is the number of shared memory;
  • semid is the number of the semaphore array;
  • nsems corresponds to the number of semaphores in the semaphore set
  • pid is the process ip, you can view details through ps -ef | grep pid
  • semnum is the number of the semaphore
  • ncount is the number of processes waiting for the signal
  • The owner is the user who created it;
  • Permissions are also called perms;
  • Bytes is the created size bytes;
  • The number of connections is the number of processes connected to the shared memory nattach;
  • The status is the status of the shared memory.
     

4. system V message queue

5. system V semaphore

6. Process mutual exclusion

  • Since each process requires shared resources, and some resources need to be used mutually exclusive, processes compete to use these resources . This relationship between processes is the mutual exclusion of processes.
  • Some resources in the system are only allowed to be used by one process at a time. Such resources are called critical resources or mutually exclusive resources. The program section involving mutually exclusive resources in the process is called a critical section.
  • Features: IPC resources must be deleted, otherwise they will not be cleared automatically unless restarted, so the life cycle of system V IPC resources depends on the kernel.

Guess you like

Origin blog.csdn.net/m0_74234485/article/details/132646671