Interprocess communication (IPC) mode

Keywords: C Linux multiple processes

Interprocess communication (IPC) mode

Inter process communication (IPC) mainly includes the following:

1,Nameless pipe( PIPE)And famous pipes( FIFO). 

2,Signal( signal). 

3,system V-IPC Shared memory.

4,system V-IPC Message queue.

5,system V-IPC Semaphore.

6,Socket.

1. Pipeline

1.1 unknown pipeline

1.2 characteristics of unknown pipeline

Characteristics of PIPE:

1,No name, so it can't be used open( ). 

2,It can only be used for communication between related processes (such as parent-child process, brother process, grandson process...).

3,Half duplex working mode: separate reading and writing ends.

4,The write operation is not atomic, so it can only be used in one-to-one simple communication.

5,out of commission lseek( )To locate.

1.3. It should be noted that

The read-write end of the anonymous pipe is fixed,Read end(fd[0])Only read operations can be performed,Write end(fd[1])Only write operations can be performed

1.4. When reading and writing data

(1)The process of writing data is dead, and the written data will still be stored in the pipeline

(2)When reading data, if there is no data in the pipeline, it will block and wait for data in the pipeline

(3)Once the data in the pipeline is read, the pipeline will be empty. It cannot be read multiple times without writing the data for the second time

     If the reading is not completed, the second reading can be carried out directly.

Example code 1

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <error.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char const *argv[])
{
	//Create anonymous pipe
	int fd[2];

	int ret = pipe(fd);
	if (ret == -1)
	{
		perror("pipe");
		return -1;
	}
	printf("Anonymous pipeline created successfully\n");
	//fd[0]: read end
	//fd[1]: write side

	int s;
	//Create affinity process (parent-child process)
	pid_t x = fork();
	char buf[100] = {0};
	char w_buf[100] = {0};
	if (x == 0)
	{
		printf("The child process starts running\n");
		read(fd[0], buf, sizeof(buf));
		printf("buf = %s\n", buf);
		printf("The subprocess ends running\n");
	}
	else
	if (x > 0)
	{
		printf("The parent process starts running\n");
		scanf("%s", w_buf);
		write(fd[1], w_buf, strlen(w_buf));

		wait(&s);
		printf("The parent process ends running\n");
	}
	else
	{
		perror("fork");
		return -1;
	}


	return 0;
}



Example code 2:

The communication between parent and child processes is realized through the nameless pipeline. The parent process can send messages to the child process, and the child process can also send messages to the parent process. Receive information and print it. For example, when sending quit, both processes end.

#include <stdio.h>
#include <sys/types.h>
#include <error.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char const *argv[])
{
	//Create anonymous pipe
	int fd[2];

	int ret = pipe(fd);
	if (ret == -1)
	{
		perror("pipe");
		return -1;
	}
	printf("Anonymous pipeline created successfully\n");
	//fd[0]: read end
	//fd[1]: write side

	int s;
	//Create affinity process (parent-child process)
	pid_t x = fork();
	char buf[100] = {0};
	char w_buf[100] = {0};
	char buf1[100] = {0};
	char w_buf1[100] = {0};
	if (x == 0)
	{
		printf("The child process starts running\n");
		while(1)
		{
			bzero(buf, sizeof(buf));
			read(fd[0], buf, sizeof(buf));
			printf("Parent process message received: %s\n", buf);
			if (strcmp(buf, "quit") == 0)
			{
				return 0;
			}
			scanf("%s", w_buf1);
			write(fd[1], w_buf1, strlen(w_buf1));
			if (strcmp(w_buf1, "quit") == 0)
			{
				return 0;
			}
			sleep(1);
		}
		
		printf("The subprocess ends running\n");
	}
	else
	if (x > 0)
	{
		printf("The parent process starts running\n");
		while(1)
		{
			scanf("%s", w_buf);
			write(fd[1], w_buf, strlen(w_buf));
			if (strcmp(w_buf, "quit") == 0)
			{
				return 0;
			}
			sleep(1);
			bzero(buf1, sizeof(buf1));
			read(fd[0], buf1, sizeof(buf1));
			printf("Child process message received: %s\n", buf1);
			if (strcmp(buf1, "quit") == 0)
			{
				return 0;
			}
		}
		

		wait(&s);
		printf("The parent process ends running\n");
	}
	else
	{
		perror("fork");
		return -1;
	}


	return 0;
}



1.2 famous pipeline

Characteristics of famous pipeline FIFO:

1,It has a name and is stored in an ordinary file system.

2,Any process with corresponding permissions can use open( )To get FIFO File descriptor for.

3,Just like ordinary files: use unified read( )/write( )To read and write.

4,Different from ordinary files: it cannot be used lseek( )For the same reason PIPE. 

5,With write atomicity, it supports multiple writers to write at the same time, and the data will not trample on each other.

6,First In First Out,First written FIFO The data is read first.

Read / write blocking:

Note: pipeline files (including pipe, FIFO and socket) cannot be opened with only the read side or only the write side

Sample code

Communication between two different processes is realized through a famous pipeline quit End both processes.

Jack    rose

Application:

//jack
//Write end
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <error.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>


#define FIFO_PATHNAME "/tmp/myfifo"

int main(int argc, char const *argv[])
{
	//Create a named pipeline (determine whether this file exists)
	if(access(FIFO_PATHNAME, F_OK))	//Determine whether this file exists
	{
		int ret = mkfifo(FIFO_PATHNAME, 0644);
		if (ret == -1)
		{
			perror("mkfifo");
			return -1;
		}
	}

	//Open named pipe
 	int fd = open(FIFO_PATHNAME, O_RDWR);
 	if (fd == -1)
 	{
 		perror("open");
		return -1;
 	}
 	printf("The named pipeline was opened successfully\n");
 	char w_buf[1024] = {0};
 	char r_buf[1024] = {0};
 	while(1)
 	{
 		bzero(r_buf, sizeof(r_buf));
 		bzero(w_buf, sizeof(w_buf));
 		//Write data
	 	scanf("%[^\n]", w_buf);
	 	write(fd, w_buf, strlen(w_buf));
	 	if (strcmp(w_buf, "quit") == 0)
		{
			return 0;
		}
	 	usleep(10);
	 	read(fd, r_buf, sizeof(r_buf));
	 	printf("rose:%s\n", r_buf);
	 	if (strcmp(r_buf, "quit") == 0)
		{
			return 0;
		}
 	}
 	



	return 0;
}
//rose
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <error.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>


#define FIFO_PATHNAME "/tmp/myfifo"

int main(int argc, char const *argv[])
{
	//Create a named pipeline (determine whether this file exists)
	if(access(FIFO_PATHNAME, F_OK))	//Determine whether this file exists
	{
		int ret = mkfifo(FIFO_PATHNAME, 0644);
		if (ret == -1)
		{
			perror("mkfifo");
			return -1;
		}
	}

	//Open named pipe
 	int fd = open(FIFO_PATHNAME, O_RDWR);
 	if (fd == -1)
 	{
 		perror("open");
		return -1;
 	}
 	printf("The named pipeline was opened successfully\n");
 	char r_buf[1024];
 	char w_buf[1024];
	while(1)
	{
		//Read data	 	
	 	bzero(r_buf, sizeof(r_buf));
		bzero(w_buf, sizeof(w_buf));
	 	read(fd, r_buf, sizeof(r_buf));
	 	if (strcmp(r_buf, "quit") == 0)
		{
			return 0;
		}
	 	printf("jack:%s\n", r_buf);

	 	scanf("%[^\n]", w_buf);
	 	write(fd, w_buf, strlen(w_buf));
	 	if (strcmp(w_buf, "quit") == 0)
		{
			return 0;
		}
	 	usleep(10);
	}
 	
	return 0;
}

2. Signal

Signal is a special kind of signal IPC,An asynchronous communication mechanism

Life cycle of signal:

Process signal generation, signal registration, signal response and processing, signal logoff

Signal response mode:

(1)Ignore signal

(2)Capture response signal function

(3)Perform default actions

Special signals:

Signals SIGKILL (- 9) and SIGSTOP (- 19) are two special signals. They cannot be ignored, blocked or captured, and can only respond according to the default action (default). In other words, for signals other than these two signals, the target process receiving the signal responds in the following order:

A) If the signal is blocked, suspend the signal and do nothing about it until it is unblocked
   Stop. Otherwise enter B. 

B) If the signal is captured, further determine the type of capture:
    
   B1) If a response function is set, the response function is executed.

   B2) If it is set to ignore, the signal is discarded directly. Otherwise enter C. 

C) Perform the default action of the signal.

Signal classification

Check the signal of the system: kill – l

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-cexvqm3o-1630930236196)( https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f55ca06f47bf421eb9b45f5ff38df40c ~tplv-k3u1fbpfcp-watermark.image)]

First 31 signals of unreliable signal and non real-time signal

characteristic:

1,Non real-time signals are not queued, and the responses of signals will be nested with each other.

2,If the target process does not respond to the non real-time signal in time, the subsequent signal will be discarded.

3,Each non real-time signal corresponds to a system event. When this event occurs, this signal will be generated.

4,If the hang signal of a process contains real-time and non real-time signals, the process will respond to the real-time signal first and will respond accordingly from large to small, rather than real       
  There is no fixed order of signals.

31 signals after reliable signal and real-time signal

1,The response order of real-time signals shall be queued according to the receiving order and shall not be nested.

2,Even if the same real-time signal is sent multiple times at the same time, it will not be discarded, but will respond one by one.

3,There is no special system event corresponding to the real-time signal.

Signal correlation function:

Signal transmission

Signal capture

//Signal response function

void func(int sig)

{

printf("signal response function \ n");

printf("sig = %d\n", sig);

}

Sig is the value of the transmitted signal

kill send signal receive

Sample code

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

//Signal response function
void func(int sig)
{
	printf("Signal response function\n");
	printf("sig = %d\n", sig);
}

int main(int argc, char const *argv[])
{
	pid_t x = fork();
	int i = 0;
	int s;
	if (x > 0) //Parent process
	{
		sleep(5);
		kill(x, 2);
		wait(&s);
	}
	else
	if (x == 0)	//Subprocess
	{
		// signal(2, SIG_IGN); 		// ignore
		// signal(2, SIG_DFL); 		// Perform default actions
		signal(2, func);		//Response signal function
		while(1)
		{
			printf("i = %d\n", i++);
			sleep(1);
			if (i == 10)
			{
				break;
			}
		}
	}
	else
	{
		perror("fork");
	}

	return 0;
}

Send to yourself:

Sample code

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

int main(int argc, char const *argv[])
{
	printf("itself ID: %d\n", getpid());
	sleep(3);
	raise(2);
	printf("11111\n");
	return 0;
}

Suspend this process:


Sample code

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

int main(int argc, char const *argv[])
{
	printf("itself ID: %d\n", getpid());
	int ret = pause();
	printf("ret=%d\n", ret);

	return 0;
}

Signal set operation function cluster

Block or release one or more signals

Sample code

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

//Signal response function
void func(int sig)
{
	printf("Captured signal %d\n", sig);
}

int main(int argc, char const *argv[])
{
	sleep(1);
	pid_t x = fork();
	
	if (x > 0) //Parent process
	{
		sleep(1);
		//Send all signals
		printf("Send signal\n");
		for (int i = 1; i < 64; ++i)
		{
			if (i==9 || i==19 || i==32 || i==33)
			{
				continue;
			}
			kill(x, i);
		}
		printf("All signals are sent\n");
	}
	else
	if (x == 0)	//Subprocess
	{
		//Register all signals with a signal response function first
		for (int i = 1; i < 64; ++i)
		{
			if (i==9 || i==19 || i==32 || i==33)
			{
				continue;
			}
			signal(i, func);
		}
		//Add these signals to the signal set
		sigset_t mysig_set;

		//Clear signal set
		sigemptyset(&mysig_set);
		//Add signal to signal set
		sigfillset(&mysig_set);

		//Block all signals and add them on the original basis
		sigprocmask(SIG_BLOCK, &mysig_set, NULL);
		sleep(5);
		//Signals to clear all blockages
		sigprocmask(SIG_UNBLOCK, &mysig_set, NULL);
		printf("Subprocess exit\n");
	}
	else
	{
		perror("fork");
	}






	return 0;
}




Realize the log system. Five clients send log information to one server. Each client sends log information at different times. Store the obtained log information in the TXT text file. The sending format is:

client1: time [2021/9/1 xx:xx:xx]

client2:

client3:

client4:

client5:

Send signal with data

Receive signal and data

The extended response function interface is as follows:

void (*sa_sigaction)(int, siginfo_t *, void *);

Parameter list details of this function:

The first parameter: int type, is the signal that triggers the function.

Second parameter: siginfo_t-type pointer, pointing to the following structure:

siginfo_t

To determine whether it is sigqueue signal transmission;

Through sinfo - > Si_ code == SI_ QUEUE

If the matching is successful, you can get the data inside: sinfo - > Si_ int

The difference between Sigqueue and kill:

Sigqueue: one with data

Kill: one without data

Difference between Signal and sigaction:

Signal: one cannot receive data, and the other uses the standard response function

Sigaction: a function that can receive data and use the extended response function. The function interface is as follows
void (*sa_sigaction)(int, siginfo_t *, void *);

Signal kernel data structure

System IPC object

Multiple processes communicate through the same key value

Key value acquisition:

Points to note for functions:

1. If the two parameters are the same, the generated key value is also the same.

2. The first parameter generally takes the directory where the process is located, because several processes that need to communicate in a project usually appear in the same directory.

3. If a process in the same directory needs more than one IPC object, it can be identified by the second parameter.

4. There is only one set of key identifiers in the system, that is, different types of IPC objects cannot be duplicated

You can use the following command to view or delete IPC objects in the current system:

Viewing message queuing: ipcs -q

View shared memory: ipcs -m

Viewing semaphores: ipcs -s
Function to obtain the key of an IPC that is not currently used

View all IPC objects: ipcs -a

Delete the specified message queue: ipcrm -q MSG_ID or ipcrm -Q msg_key

Delete the specified shared memory: ipcrm -m SHM_ID or ipcrm -M shm_key

Delete the specified semaphore: ipcrm -s SEM_ID or ipcrm -S sem_key

Message queuing (MSG)

Message queuing provides a special pipeline with data identification, so that each segment of written data becomes identified
 Message. The process reading this message can read it correctly as long as this ID is specified without being disturbed by other messages

The general usage of message queue is:

1. Sender:

A) Gets the name of the message queue ID
B) Put the data into a special structure with identification and send it to the message queue.

2. Receiver:

A) Gets the name of the message queue ID
B) Read out the message with the specified ID.

Get message queue ID

Sending and receiving data

Close message queue

Sample code

Create three processes, Xiaohong, Xiaoming and Xiaoliang. Xiaoming and Xiaoliang say I like you to Xiaohong respectively. Xiaohong receives information from them. Xiaohong says I like you too to Xiaoming and says sorry,you are a goodboy to Xiaoliang.
Use message queuing to complete.

Shared memory

The general steps for using shared memory are:

1,Gets the name of the shared memory object ID
2,Map the shared memory to an area of the virtual memory space of the process
3,When it is no longer used, the mapping relationship is released
4,When no process needs this shared memory anymore, delete it.

Shared memory ID acquisition

Shared memory mapping

Delete shared memory

Semaphore

1,Resources (variables, linked lists, files, etc.) that may be accessed by multiple processes or threads at the same time are called shared resources, also known as critical resources( critical resources). 

2,The code that accesses these resources is called critical code, and these code areas are called critical areas( critical zone). 

3,Before the program enters the critical area, it must apply for resources. This action is called P Operation, it's like applying to the security guard before you drive into the parking lot
   Like a parking card, P The operation is to apply for resources. If the application is successful, the number of resources will be reduced. If the application fails, either wait at the door or leave.

4,After the program leaves the critical area, it must release the corresponding resources. This action is called V Operation, it's like returning the parking card to the security guard after you leave the parking lot,
   V Operation is to release resources. Releasing resources is to increase the number of resources.

Solve the problem of resource competition

The system semaphore has the same write atomicity as the well-known pipeline

Semaphore ID acquisition

Initialization semaphore

P/V operation of semaphore

Named semaphore:

(1) Name: "/ myname"
Note: the name must start with /

(2) The pthread Library (Thread Library) is required to use a named semaphore
How do I use this semaphore?

1,adopt sem_open(),Open semaphore

2,Directly through sem_wait(),sem_post()conduct P,V operation

3,adopt sem_close()Off semaphore

4,adopt sem_unlink()Delete semaphores and release resources
Sem_open()

 

#include <fcntl.h>           /* For O_* constants */

#include <sys/stat.h>        /* For mode constants */

#include <semaphore.h>

sem_t *sem_open(const char *name, int oflag);

sem_t *sem_open(const char *name, int oflag,

                       mode_t mode, unsigned int value);

 

adopt sem_wait conduct P Operation (release, return)

#include <semaphore.h>

 

int sem_wait(sem_t *sem);

int sem_trywait(sem_t *sem);

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

 

conduct V operation sem_post()conduct V operation

#include <semaphore.h>

int sem_post(sem_t *sem);

 

Off semaphore

#include <semaphore.h>

int sem_close(sem_t *sem);

 

Delete semaphore

#include <semaphore.h>

int sem_unlink(const char *name);

 

compile:

Gcc name.c –o name -lpthread

Posted by trent2800 on Mon, 06 Sep 2021 20:12:34 -0700