IPC inter-process communication and sample code

1. What is process communication?

        InterProcess Communication (IPC) refers to the exchange of information between processes . In fact, process synchronization and mutual exclusion are essentially a kind of process communication (this is why we will see semaphores and PV operations in the process communication mechanism later), but it only transmits semaphores. By modifying the semaphore, processes can establish connections, coordinate and work together, but it lacks the ability to transfer data .

        Although there are some situations where the amount of information exchanged between processes is very small, such as only exchanging certain status information, the synchronization and mutual exclusion mechanism of the process can fully do the job. But in most cases, a large amount of data needs to be exchanged between processes , such as transmitting a batch of information or an entire file, which requires a new communication mechanism, which is the so-called process communication.

        Let’s look at some process communications intuitively from the operating system level: We know that in order to ensure security, the user address space of each process is independent. Generally speaking, one process cannot directly access the address space of another process, but the kernel space is It is shared by each process, so information exchange between processes must go through the kernel .

Let’s list the common process communication mechanisms provided by the Linux kernel:

  • Pipes (also called shared files)
  • Message queue (also called message passing)
  • Shared memory (also called shared storage)
  • Semaphores and PV operations
  • Signal
  • Socket

2. Pipeline

1. Anonymous pipe

        Pipes are a half-duplex communication method. Data can only flow in one direction and can only be used between processes that are related. Process affinity usually refers to the parent-child process relationship. If we want to achieve mutual communication (full-duplex communication), we need to create two pipes. In addition, the pipe created through the pipe symbol | is an anonymous pipe and will be automatically destroyed when used up. Moreover, anonymous pipes can only be used between processes that have a relationship (parent-child process). In other words, anonymous pipes can only be used for communication between parent and child processes .

In the actual coding of Linux, anonymous pipes are created through the pipe function. If the creation is successful, 0 is returned, and -1 is returned if the creation fails:

#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
	pid_t pid1;
	int fields[2];
	char buffer[80];
	char s[100];
	char ss[100];
	if(pipe(fields)!=0){
		fprintf(stderr,"Createpipe error:%s\n\a",strerror(errno));
		exit(1);
	}
	if((pid1=fork())<0)printf("fork child error!\n");
/* 子进程写入数据 */
	if(pid1==0){
	printf("fork child,child is sending a message !\n");
	char s[]="hello!\n";
	write(fields[1],s,sizeof(s));
    exit(0)
		}
/* 父进程读取数据 */
	else 
	{
	printf("parent read start !\n");
	read(fields[0],buffer,80);
printf("parent receive the message:%s",buffer);
	}
	exit (0);
}

Compile and run 

cc -o unamepipe unamepipe.c -g
./unamepipe

operation result 

2. Named pipes

        Named pipe fifo solves the problem that pipes can only communicate with related processes. Implementing a named pipe is actually implementing a FIFO file. Once a named pipe is established, its subsequent reading and closing operations are exactly the same as ordinary pipes. Although the inode node of the FIFO file is on the disk, it is only one node. The data of the file is still stored in the kernel buffer page, the same as an ordinary pipe.

Use the Linux command mkfifo to create a named pipe:

$ mkfifo myPipe

myPipe is the name of this pipe. Next, we write data to the famous pipe myPipe: 

$ echo "hello" > myPipe

        After executing this line of command, you will find that it stops here. This is because the content in the pipe has not been read. The command can exit normally only after the data in the pipe is read. So, we execute another command to read the data in this famous pipe: 

$ cat < myPipe
hello

The program source code example is as follows:

//读进程
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define FIFO_PATH "myfifofile"
int main()
{
	int fd;
	char cont_r[255];
#创建命名管道
	if(mkfifo(FIFO_PATH,0666)<0 && errno!=EEXIST)
	{
	
		perror("create fifo failed");
		return -1;

	}else
	{
	  	printf("create fifo success\n");
    #打开文件进行读操作
		fd =open(FIFO_PATH,O_CREAT|O_RDONLY,0666);
		if(fd>0)
		{
			while(1){
				read(fd,cont_r,255);
				printf("read:%s\n",cont_r);
			}
			close(fd);
		}else
			perror("open failed");

	}
	return 0;
}
//写进程
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define FIFO_PATH "myfifofile"
int main()
{
        int fd;
        char cont_w[] = "hello sundy";

        if(mkfifo(FIFO_PATH,0666)<0 && errno!=EEXIST)
        {

                perror("create fifo failed");
                return -1;

        }else
        {
                printf("create fifo success\n");

                fd =open(FIFO_PATH,O_CREAT|O_WRONLY,0666);
                if(fd>0)
                {
                        while(1){
                                write(fd,cont_w,strlen(cont_w));
                                printf("write success\n");
				                   sleep(2);
                        }
                        close(fd);
                }else
                        perror("open failed");

        }
        return 0;
}

Compile and run
, open two terminals and execute

3. Message queue

        It can be seen that although the process communication method of pipes is simple to use, it is relatively inefficient and is not suitable for frequent exchange of data between processes, and pipes can only transmit unformatted byte streams . For this purpose, the message passing mechanism (called message queue in Linux) was born. For example, if process A wants to send a message to process B, process A can return normally after putting the data in the corresponding message queue. Process B can just read the data from the message queue by itself when needed. The same is true when process B wants to send a message to process A.

The essence of a message queue is a linked list of messages stored in memory, and messages are essentially user-defined data structures . If a process reads a message from the message queue, the message will be deleted from the message queue. Compare the pipeline mechanism:

  • A message queue allows one or more processes to write or read messages to it.
  • The message queue can realize random query of messages . It is not necessary to read messages in first-in, first-out order. It can also be read according to the type of message. It has more advantages than the first-in-first-out principle of the famous pipeline.
  • For message queues, before a process writes a message to a queue, there is no need for another process to wait for the message to arrive on the message queue. For pipes, unless the reading process already exists, it makes no sense for the writing process to perform the writing operation first.
  • The life cycle of the message queue depends on the kernel. If the message queue is not released or the operating system is not shut down, the message queue will always exist. The anonymous pipe is established when the process is created and destroyed when the process ends.

It is important to note that message queues are useful for exchanging smaller amounts of data because there are no conflicts to avoid. However, when a user process writes data to the message queue in the memory, the process of copying the data from the user state to the kernel state will occur; similarly, when another user process reads the message data in the memory, a process of copying the data from the kernel state will occur. The process of copying data to user mode. Therefore, if the amount of data is large, using the message queue will cause frequent system calls, which means it will take more time for the kernel to intervene .

related functions

The message data format is as follows

The source program example is as follows:

// 写进程 
#include <stdio.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 
  
// 消息队列数据结构
struct mesg_buffer { 
    long mesg_type; 
    char mesg_text[100]; 
} message; 
  
int main() 
{ 
    key_t key; 
    int msgid; 
  
    // ftok to generate unique key 
    key = ftok("progfile", 65); 
  
    // msgget creates a message queue 
    // and returns identifier 
    msgid = msgget(key, 0666 | IPC_CREAT); 
    message.mesg_type = 1; 
  
    printf("Write Data : "); 
    gets(message.mesg_text); 
  
    // msgsnd to send message 
    msgsnd(msgid, &message, sizeof(message), 0); 
  
    // display the message 
    printf("Data send is : %s \n", message.mesg_text); 
  
    return 0; 
}

 

// 读进程
#include <stdio.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 
  
// structure for message queue 
struct mesg_buffer { 
    long mesg_type; 
    char mesg_text[100]; 
} message; 
  
int main() 
{ 
    key_t key; 
    int msgid; 
  
    // ftok to generate unique key 
    key = ftok("progfile", 65); 
  
    // msgget creates a message queue 
    // and returns identifier 
    msgid = msgget(key, 0666 | IPC_CREAT); 
  
    // msgrcv to receive message 
    msgrcv(msgid, &message, sizeof(message), 1, 0); 
  
    // display the message 
    printf("Data Received is : %s \n",  
                    message.mesg_text); 
  
    // to destroy the message queue 
    msgctl(msgid, IPC_RMID, NULL); 
  
    return 0; 
}

operation result

 

4. Shared memory

        In order to avoid copying messages and making system calls as frequently as message queues, the shared memory mechanism emerged. As the name suggests, shared memory allows unrelated processes to connect the same physical memory to their respective address spaces, so that these processes can access the same physical memory, and this physical memory becomes shared memory. If a process writes data to shared memory, the changes will immediately affect any other process that has access to the same segment of shared memory.

        Collecting the content of memory management, let’s deeply understand the principles of shared memory. First of all, each process has its own process control block (PCB) and logical address space (Addr Space), and has a corresponding page table, which is responsible for comparing the logical address (virtual address) of the process with the physical address. Mapping,managed through the Memory Management Unit (MMU). The logical addresses of two different processes are mapped to the same area of ​​physical space through the page table, and the area they jointly point to is shared memory .

         Different from the frequent system calls of the message queue, for the shared memory mechanism, system calls are only required when establishing a shared memory area. Once the shared memory is established, all accesses can be accessed as regular memory without resorting to the kernel. In this way, data does not need to be copied back and forth between processes, so this is the fastest way to communicate between processes.

related functions

shmget: apply for shared memory
shmat: establish a mapping from user process space to shared memory
shmdt: cancel the mapping relationship
shmctl: reclaim shared memory space

Program source code example

//写进程
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 
  
int main() 
{ 
    // ftok to generate unique key 
    key_t key = ftok("shmfile",65); 
  
    // shmget returns an identifier in shmid 
    int shmid = shmget(key,1024,0666|IPC_CREAT); 
  
    // shmat to attach to shared memory 
    char *str = (char*) shmat(shmid,(void*)0,0); 
  
    gets(str); 
  
    printf("Data written in memory: %s\n",str); 
      
    //detach from shared memory  
    shmdt(str); 
  
    return 0; 
}
//读进程
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <stdio.h> 

  
int main() 
{ 
    // ftok to generate unique key 
    key_t key = ftok("shmfile",65); 
  
    // shmget returns an identifier in shmid 
    int shmid = shmget(key,1024,0666|IPC_CREAT); 
  
    // shmat to attach to shared memory 
    char *str = (char*) shmat(shmid,(void*)0,0); 
  
    printf("Data read from memory: %s\n",str); 
      
    //detach from shared memory  
    shmdt(str); 
    
    // destroy the shared memory 
    shmctl(shmid,IPC_RMID,NULL); 
     
    return 0; 
}

Compile and run

5. Semaphore and PV operations

        In fact, recent research on systems with multiple CPUs shows that message passing actually outperforms shared memory on such systems because message queues do not need to avoid conflicts, whereas shared memory mechanisms can . That is to say, if multiple processes modify the same shared memory at the same time, the content written by the first process will be overwritten by the later one. Moreover, in a multi-channel batch processing system, multiple processes can be executed concurrently, but due to the limited resources of the system, the execution of the processes is not consistent, but stops and goes, advancing at an unpredictable speed ( asynchronicity). But sometimes we hope that multiple processes can work closely together and execute them in a specific order to achieve a common task.

        For example, if there are two processes A and B, which are responsible for reading and writing data respectively, these two threads cooperate with each other and depend on each other. Then writing data should occur before reading data. In fact, due to the existence of asynchrony, reading first and then writing may occur. At this time, because the buffer has not been written with data, reading process A has no data to read, so reading process A is blocked.

        Therefore, in order to solve the above two problems, ensure that only one process is accessing the shared memory at any time (mutual exclusion), and enable processes to access the shared memory in a specific order (synchronization), we can use process synchronization and mutual exclusion mechanisms, common ones such as semaphores and PV operations.

        A semaphore is an atomic counter, which is equivalent to a lock. When each process wants to access a critical resource, it must obtain a lock from the semaphore so that it can enter the "room" of the critical resource and lock the door. Do not allow other processes to come in. At this time, the semaphore performs the P() operation. The number of locks is reduced by one, so the counter decreases by 1. When its access is completed, it comes out, returns the lock to the semaphore, and performs the V() operation. , the counter increases by 1;

Program source code example:

Let the two processes print AA and BB to the monitor respectively (everything under Linux is a file, a critical resource). When there is no semaphore for protection, data confusion will occur, for example: "AABBABAAAB...". In order to solve this problem, we created Semaphores are protected. Print "AA" or "BB"

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/sem.h>

union semun{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	//struct seminfo *buff;	
};

static int set_semvalue(void);
static void del_semvalue(void);
static int semaphore_p(void);
static int semaphore_v(void);
static int sem_id;

int main(int argc, char *argv[])
{
	int i;
	int pause_time;
	char op_char = 'O';
	srand((unsigned int)getpid());

	sem_id =semget((key_t)1234, 1, 0666 | IPC_CREAT);

/* 如果程序第一个被调用,也就是调用时含有一个参数,使得argc>1,此时就调用set_semvalue初始化信号量,并将op_char设置为x*/
	if (argc > 1){
		if(!set_semvalue()){
			fprintf(stderr, "Failed to initialize semaphore\n");
			exit(EXIT_FAILURE);
		}
		op_char = 'X';
		sleep(2);
	}

/*进入和离开临界区10次,每次循环开始的时候首先调用semaphore_p函数,它在程序将进入临界区域时设置信号量以等待进入*/
	for(i=0; i<10; i++){
		if(!semaphore_p()) exit(EXIT_FAILURE);
		printf("%c", op_char);fflush(stdout);
		pause_time = rand() % 3;
		sleep(pause_time);
		printf("%c", op_char);fflush(stdout);

/*进入临界区域后,调用semaphore_v将信号量设置为可用,然后等待一段随机的时间,再进入下一次循环*/
		if(!semaphore_v()) exit(EXIT_FAILURE);
		pause_time = rand() % 2;
		sleep(pause_time);
	}
	printf("\n%d - finished\n", getpid());
	if (argc > 1)
	{
		sleep(10);
		del_semvalue();
	}
	exit(EXIT_SUCCESS);
}

/*该函数用来将semctl调用的command参数设置为SETVAL来初始化信号量*/
static int set_semvalue(void)
{
	union semun sem_union;
	
	sem_union.val = 1;
	if (semctl(sem_id, 0, SETVAL, sem_union)==-1) return 0;
	return (1);
}
/*通过调用semctl调用的command设置为IPC_RMID来删除信号量ID*/
static void del_semvalue(void)
{
	union semun sem_union;

	if (semctl(sem_id, 0, IPC_RMID, sem_union)==-1)
	fprintf(stderr, "Failed to delete semaphore");
}

/*对信号量执行减1操作*/
static int semaphore_p(void)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id, &sem_b, 1) == -1){
		fprintf(stderr,"semaphore_p failed\n");
		return (0);
	}
	return(1);
}

/*对信号量执行加1操作*/
static int semaphore_v(void)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id, &sem_b, 1) == -1){
		fprintf(stderr,"semaphore_v failed\n");
		return (0);
	}
	return(1);
}

Compile and run

Source code example 2 is almost the same as the above code, except that it becomes a semaphore mechanism between parent and child processes.

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/sem.h>
#include<sys/ipc.h>
#include<sys/types.h>

static int set_semvalue(void);
static void del_semvalue(void);
static int semaphore_p(void);
static int semaphore_v(void);
static int sem_id;

union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    //struct seminfo *buff; 
};
int main(int argc, char *argv[])
{
    int i;
    int pause_time;
    char op_char = 'O';
    srand((unsigned int)getpid());

    sem_id =semget((key_t)1234, 1, 0666 | IPC_CREAT);
    int id = fork();
    if(id<0)
    {
        perror("fork failed\n");
        return -1;
    }

    else if (id>0){
        if(!set_semvalue()){
            fprintf(stderr, "Failed to initialize semaphore\n");
            exit(EXIT_FAILURE);
        }
        op_char = 'X';
        sleep(2);
    }
    for(i=0; i<10; i++){
        if(!semaphore_p()) exit(EXIT_FAILURE);
        printf("%c", op_char);fflush(stdout);
        pause_time = rand() % 3;
        sleep(pause_time);
        printf("%c", op_char);fflush(stdout);
        if(!semaphore_v()) exit(EXIT_FAILURE);
        pause_time = rand() % 2;
        sleep(pause_time);
    }
    printf("\n%d - finished\n", getpid());
    if (id> 0)
    {
        sleep(10);
        del_semvalue();
    }
    exit(EXIT_SUCCESS);
}

static int set_semvalue(void)
{
    union semun sem_union;
    
    sem_union.val = 1;
    if (semctl(sem_id, 0, SETVAL, sem_union)==-1) return 0;
    return (1);
}

static void del_semvalue(void)
{
    union semun sem_union;

    if (semctl(sem_id, 0, IPC_RMID, sem_union)==-1)
    fprintf(stderr, "Failed to delete semaphore");
}
static int semaphore_p(void)
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1){
        fprintf(stderr,"semaphore_p failed\n");
        return (0);
    }
    return(1);
}
static int semaphore_v(void)
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1){
        fprintf(stderr,"semaphore_v failed\n");
        return (0);
    }
    return(1);
}

Compile and run

Here we can see that the pid of the child process is the pid of the parent process + 1. Note that the return value of fork to create a child process is 0, which is different from the pid here.

6. Signal

Notice! Signals and semaphores are two completely different concepts !

        Signal is the only asynchronous communication mechanism among process communication mechanisms. It can send signals to a process at any time. Notify the process of the sending of an asynchronous event by sending a specified signal to force the process to execute the signal handler. After the signal is processed, the interrupted process will resume execution . Users, the kernel, and processes can generate and send signals.

        The sources of signal events mainly include hardware sources and software sources. The so-called hardware source means that we can input certain key combinations through the keyboard to send signals to the process. For example, the common key combination Ctrl+C generates a SIGINT signal, which means to terminate the process; and the software source means that we can send signals to the process through the kill series of commands. For example, kill -9 1111 means sending the SIGKILL signal to the process with PID 1111 to terminate it immediately.

Program source code example

In the form of a simulated alarm clock, inter-process communication is represented by sending a SIGALRM signal from one process to another process.

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

static int alarm_fired = 0;

/*该函数用来模拟闹钟*/
void ding(int sig)
{
    alarm_fired =1;
}

/*main函数中告诉子进程在等待5秒后发送SIGALRM信号给它的父进程*/
int main()
{
    pid_t pid;
    printf("alarm start\n");
    pid = fork();  /*创建子进程*/
    switch (pid)
    {
    case -1:
        perror("fork failed");
        exit(1);
    
    case 0:
        sleep(5);  /*子进程休眠5秒*/
        kill(getppid(), SIGALRM);  /*子进程在5秒后将SIGALRM信号传递给父进程*/
        exit(0);
}

/*父进程通过一个signal调用捕获SIGALRM信号的工作,等待该信号的到来*/
    printf("waitting for alarm to go on\n");
    (void) signal(SIGALRM, ding);
    pause();
    if (alarm_fired)
        printf("ding!\n");
    printf("done\n");
    exit(0);
}

Compile and run

7. Socket

        So far, the five methods introduced above are all used to communicate between processes on the same host. If you want to communicate with processes on different hosts across the network , what should you do? This is what Socket communication does ( of course, Socket can also complete communication with processes on the host ).

        Socket is a communication mechanism. With this mechanism, the development of client/server (that is, the process to communicate) system can be carried out on a local stand-alone machine or across a network. That is, it allows processes on computers that are not on the same computer but are connected through a network to communicate. Because of this, sockets clearly distinguish clients from servers.

 Program source code example

 //服务器
    #include <unistd.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <signal.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
     int main()  
    {  
        int server_sockfd = -1;  
        int client_sockfd = -1;  
        int client_len = 0;  
        struct sockaddr_in server_addr;  
        struct sockaddr_in client_addr;  
        //创建流套接字  
        server_sockfd = socket(AF_INET, SOCK_STREAM, 0);  
        //设置服务器接收的连接地址和监听的端口  
        server_addr.sin_family = AF_INET;//指定网络套接字  
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的连接  
        server_addr.sin_port = htons(9736);//绑定到9736端口  
        //绑定(命名)套接字  
        bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));  
        //创建套接字队列,监听套接字  
        listen(server_sockfd, 5);  
        //忽略子进程停止或退出信号  
        signal(SIGCHLD, SIG_IGN);  
          
        while(1)  
        {  
            char ch = '\0';  
            client_len = sizeof(client_addr);  
            printf("Server waiting\n");  
            //接受连接,创建新的套接字  
            client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len);  
      
            if(fork() == 0)  
            {  
                //子进程中,读取客户端发过来的信息,处理信息,再发送给客户端  
                read(client_sockfd, &ch, 1);  
                sleep(5);  
                ch++;  
                write(client_sockfd, &ch, 1);  
                close(client_sockfd);  
                exit(0);  
            }  
            else  
            {  
                //父进程中,关闭套接字  
                close(client_sockfd);  
            }  
        }  
    }  

 

 //客户端
    #include <unistd.h>  
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #include <stdio.h>  
    #include <stdlib.h>  
      
    int main()  
    {  
        int sockfd = -1;  
        int len = 0;  
        struct sockaddr_in address;  
        int result;  
        char ch = 'A';  
        //创建流套接字  
        sockfd = socket(AF_INET, SOCK_STREAM, 0);  
        //设置要连接的服务器的信息  
        address.sin_family = AF_INET;//使用网络套接字  
        address.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器地址  
        address.sin_port = htons(9736);//服务器所监听的端口  
        len = sizeof(address);  
        //连接到服务器  
        result = connect(sockfd, (struct sockaddr*)&address, len);  
      
        if(result == -1)  
        {  
            perror("ops:client\n");  
            exit(1);  
        }  
        //发送请求给服务器  
        write(sockfd, &ch, 1);  
        //从服务器获取数据  
        read(sockfd, &ch, 1);  
        printf("char form server = %c\n", ch);  
        close(sockfd);  
        exit(0);  
    }  

Compile and run

8. Summary

Let’s briefly summarize the above six process communication mechanisms provided by the Linux kernel:

1) First of all, the simplest way is a pipeline . The essence of a pipeline is a special file stored in memory. In other words, the kernel opens up a buffer in memory, which is associated with the pipe file. Operations on the pipe file are converted by the kernel into operations on this buffer. Pipes are divided into anonymous pipes and named pipes. Anonymous pipes can only communicate between parent and child processes, while named pipes have no restrictions.

2) Although pipes are simple to use, they are relatively inefficient and are not suitable for frequent data exchange between processes, and pipes can only transmit unformatted byte streams. Born for this message queue application. The essence of a message queue is a linked list of messages stored in memory, and messages are essentially user-defined data structures. If a process reads a message from the message queue, the message will be deleted from the message queue.

3) The message queue is relatively slow because each data writing and reading requires a data copy process between user mode and kernel mode. Shared memory can solve this problem. The so-called shared memory is: the logical addresses of two different processes are mapped to the same area of ​​​​physical space through the page table, and the area they jointly point to is shared memory. If a process writes data to shared memory, the changes will immediately affect any other process that has access to the same segment of shared memory.

For the shared memory mechanism, system calls are only required when establishing a shared memory area. Once the shared memory is established, all accesses can be performed as regular memory accesses without the help of the kernel. In this way, data does not need to be copied back and forth between processes, so this is the fastest way to communicate between processes.

4) Although shared memory is very fast, there is a conflict problem. For this reason, we can use semaphores and PV operations to achieve mutually exclusive access to shared memory, and can also achieve process synchronization.

5) Signals and semaphores are two completely different concepts! Signal is the only asynchronous communication mechanism among process communication mechanisms. It can send signals to a process at any time. Notify the process of the sending of an asynchronous event by sending a specified signal to force the process to execute the signal handler. After the signal is processed, the interrupted process will resume execution. Users, the kernel, and processes can generate and send signals.

6) The five methods introduced above are all used for communication between processes on the same host. If you want to communicate with processes on different hosts across the network, you need to use Socket  communication  . In addition, Socket can also complete communication with processes on the host.

 

Guess you like

Origin blog.csdn.net/u013253075/article/details/132639710