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