Unnamed pipe (half-duplex): (only the same program can run)
Creating an unnamed pipe will generate a special file that only exists in memory
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> //int pipe(int pipefd[2]); //ssize_t write(int fd, const void *buf, size_t count); int main() { int pid; int fd[2]; char buf[128]; if(pipe(fd) == -1){ //Create an unnamed pipe printf("create pipe failed!\\ "); } pid = fork();//Create a process if(pid < 0){ printf("creat fork failed!\\ "); }else if(pid > 0){//parent process sleep(3); //Delay for 3 seconds printf("This is father!\\ "); close(fd[0]); //Close the read channel write(fd[1],"Hello , From Father!",strlen("Hello , From Father!")); //write channel to child process wait();//Wait for the child process to exit and collect the exit signal }else{ //subprocess printf("This is Child!\\ "); close(fd[1]);//Close the write channel read(fd[0],buf,128);//Read the data sent by the parent process of the channel printf("read from father:%s\\ ",buf);//print the read data exit(0);//exit signal } return 0; }
The running effect is as follows: (Because the parent process waits for 3 seconds, the child process runs first, and the parent process runs after waiting for 3 seconds)
Named pipe fifo: (can be run by different programs)
Creating a named pipe will exist in the file system as a special device file, such as the file I created below
Program A: (mkfifo) create pipe (read) read
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> // int mkfifo(const char *pathname, mode_t mode); int main() { char buf[30] = {0}; int nread = 0; if((mkfifo("./file",0600) == -1) & amp; & amp; errno!= EEXIST)//Create a named pipe, readable and writable { printf("mkfifo file failed!\\ "); perror("why:");//perror function gets failure information } int fd = open("./file",O_RDONLY);//Open the pipe file in read-only mode while (1) { nread = read(fd,buf,30);//read the data in the pipeline printf("read=?yte from buf:%s\\ ",nread,buf);//print the number of bytes read and data content } close(fd);//close the file return 0; }
Program B: (write) write
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> #include <string.h> // int mkfifo(const char *pathname, mode_t mode); int main() { int cnt = 0; char *buf = "Ivan hen shuai!"; //string to be written int fd = open("./file",O_WRONLY);//Write-only way to punch file printf("write open success\\ "); while(1){ //Break out of the loop after writing 5 times write(fd,buf,strlen(buf));//write sleep(1);//Delay for one second to wait for writing to the cache if(cnt == 5){ break; } } close(fd);//close the file return 0; }
The operation effect is as follows: (run program A first, wait for the data to be written into the read data, then run program B, write the data, and finally program A prints the read data) (fiforead is program A, fifowrite is program B)
Message queue: msg (can be run by different programs)
In the Linux kernel, there is a special structure linked list to manage and store message queues
Ideas: 1. How does A add messages to the queue
2. How does B get the message from the queue
Program A: msgget
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <string.h> //ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[128]; /* message data */ }; struct msgbuf readbuf; int main() { int key; key = ftok(".",'z');//Analyzed into key by ftok function printf("key=%x\\ ",key); //Each message queue has an id number int msgID = msgget(key,IPC_CREAT|0777);//create/get message queue, readable, writable and executable if(msgID == -1){ printf("get que failed!\\ "); } //Read the content written into the queue, the message type length is 888, and the number is 0 msgrcv(msgID, &readbuf,sizeof(readbuf.mtext),888,0); // print the read data printf("read from que:%s\\ ",readbuf.mtext); //Create data, which is a structure type, and the length of the message type is 988 struct msgbuf sendbuf = {988,"Thank you for reach!\\ "}; //The msgsend function writes the data of the structure into the queue msgsnd(msgID, & amp; sendbuf, strlen(sendbuf.mtext), 0); //After the program is used up, remove the unused garbage queue msgctl(msgID, IPC_RMID, NULL); return 0; }
Program B: msgsend (the whole is similar to msgget, but it depends on who sends it first and who reads it first)
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <string.h> //ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); struct msgbuf { long mtype; /* message type, must be > 0 */ char mtext[128]; /* message data */ }; struct msgbuf readbuf; struct msgbuf sendbuf = {888,"This is maessage from queue!\\ "}; int main() { int key; key = ftok(".",'z'); printf("key=%x\\ ",key); int msgID = msgget(key,IPC_CREAT|0777); if(msgID == -1){ printf("get que failed!\\ "); } //msgsend function reads the data in the queue msgsnd(msgID, & amp; sendbuf, strlen(sendbuf.mtext), 0); printf("send over!\\ "); //Send data to the queue msgrcv(msgID, &readbuf,sizeof(readbuf.mtext),988,0); printf("return from que:%s\\ ",readbuf.mtext); // Talk about garbage queue removal msgctl(msgID, IPC_RMID, NULL); return 0; }
The operation effect is as follows: (run program A first, wait for the data to be written into the read data, then run program B, write the data, and finally program AB prints the read data) (msgget is program A, msgsend is program B)
Memory sharing: shm (can be run by different programs)
Memory sharing, as the name implies, they can share a certain memory
Idea: 1. First create/acquire a shared memory
2. The file is connected to this memory
3. Release memory
4. Remove the memory
Program A: Shaget
#include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // int shmget(key_t key, size_t size, int shmflg); int main() { int shmID; key_t key; char *shmaddr; key = ftok(".",1);//Get key value shmID = shmget(key,1024*4,IPC_CREAT|0666);//Create shared memory, readable and writable, generate a memory id number if(shmID == -1){ printf("get failed!\\ "); } /*Connect this memory, the first 0 is the default, the second line 0 means that the mapped content is readable and writable Generate a pointer variable and point to memory*/ shmaddr = shmat(shmID,0,0); printf("shmat ok!\\ ");//Connect successfully strcpy(shmaddr,"Ivan nb123!");//Write the string into the pointer variable sleep(5);//wait for 5 seconds shmdt(shmaddr);//release memory shmctl(shmID,IPC_RMID,0);//Remove the memory printf("quit\\ "); return 0; }
Program B: share
#include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // int shmget(key_t key, size_t size, int shmflg); int main() { int shmID; key_t key; char *shmaddr; key = ftok(".",1); shmID = shmget(key,1024*4,0);//Get if(shmID == -1){ printf("get failed!\\ "); } shmaddr = shmat(shmID,0,0);//connect this memory printf("data:%s\\ ",shmaddr);//print out the data in memory printf("shmat ok!\\ "); // sleep(5); shmdt(shmaddr);//release memory //shmctl(key,IPC_RMID,0);//Because the program has already removed the memory operation, so it is not used here printf("quit\\ "); return 0; }
The operation effect is as follows: (run program A first, wait for the data to be written into the memory, then run program B, read the data, and finally program B prints the read data) (shmg is program A, shmr is program B)
Signal: sig (can be run by different programs)
For Linux, the signal is like a hardware interrupt in a microcontroller, this signal is a “soft interrupt”
There are three ways of signal processing: ignore, capture signal, default action
(SIGKILL and SIGSTOP cannot be ignored, they are ctl+C and ctl+Z)
Each signal has a name and a number, all beginning with SIG
Use kill -l to see what signals are in linux
For example, when program A cannot exit, we can call it on the other end of cmd this signal
Such as KILL (pid:-9, which is SIGKILL) (pid number of A program)
The premise is that we let program A bind the KILL signal to kill the process
The above is the operation of the low-level signal, and the following is directly on the high-level signal operation:
Go directly to the code demo
Program A: sigaction receiving signal
#include <signal.h> #include <stdio.h> //int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); //Function pointer, the first is the num of the program, the second is the structure, and the third is non-empty and can receive data void handler(int signum, siginfo_t *info, void *context) { printf("get signum:%d\\ ",signum);//print out the num of the program if(context != NULL){//Non-empty data can be received printf("get data:%d\\ ",info->si_int);//print out the integer data in the structure printf("get data:%d\\ ",info->si_value.sival_int);// optional printf("form:%d\\ ",info->si_pid);//Print out the pid of program B } } int main() { struct sigaction act; printf("pid = %d\\ ",getpid());//Print out the pid number of this program act.sa_sigaction = handler;//Additional receiving data, which is a function pointer act.sa_flags = SA_SIGINFO;// Receive signal default //The first parameter is a custom semaphore, the second is a structure, binding function, and the third is a backup, which can be NULL sigaction(SIGUSR1, & amp;act,NULL);//Process signal function registration while(1); return 0; }
Program B: sigaqueue signaling
#include <signal.h> #include <stdio.h> //int sigqueue(pid_t pid, int sig, const union sigval value); int main(int argc, char **argv) { int signum; int pid; signum = atoi(argv[1]); //Because signum is an integer, call atoi to force conversion of ASI code pid = atoi(argv[2]); //Because pid is an integer, call atoi to force conversion of ASI code union sigval value; value.sival_int = 100; sigqueue(pid,signum,value); //Signal, the third parameter is the union, which stores the data to be sent printf("pid=%d,done\\ ",getpid()); return 0; }
The running effect is as follows: (program B is for sending signals, and program A is for receiving signals)
Semaphore
It is not a communication method, it is a usage that is attached to the above other communication methods in the form of a lock
It decides who runs first and who runs later,
It can be understood as:
key: semaphore, semaphore set
Room: Critical Resources (Printers)
There are two operations:
1. P operation (pgetkey) to get the key
2. V operation (vputbackkey) to put the key back
The above code understanding:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> //int semget(key_t key, int nsems, int semflg); //int semop(int semid, struct sembuf *sops, unsigned nsops) union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct semiinfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */ }; void pGetKey(int id) { struct sembuf sops; sops.sem_num = 0;//The number of the semaphore sops.sem_op = -1; //Get the key operation sops.sem_flg = SEM_UNDO;//When the process automatically terminates, cancel the lock operation (blocking) semop(id, &sops, 1); printf("get keys!\\ "); } void vPutBackKey(int id) { struct sembuf sops; sops.sem_num = 0;//The number of the semaphore sops.sem_op = 1; //Get the key operation sops.sem_flg = SEM_UNDO;//When the process automatically terminates, cancel the lock operation (blocking) semop(id, &sops, 1); printf("put back keys!\\ "); } int main() { int semi; key_t key; key = ftok(".",2); // There is a semaphore in the semaphore collection semid = semget(key,1,IPC_CREAT|0666);//create/get semaphore union semun initsem; initsem.val = 0; //Operate the 0th semaphore number 0 semctl(semid,0,SETVAL,initsem); //SETVAL sets the value of the semaphore, set to initsem int pid = fork(); if(pid > 0){ // go get the lock pGetKey(semid); printf("This is Father\\ "); // put the lock back vPutBackKey(semi); semctl(semid,0,IPC_RMID);//Destroy the lock }else if(pid == 0){ //There is no lock here, because there is no lock in the initial state, wait until the parent process does not execute, come here printf("This is Child\\ "); // At this time, the lock operation is called, and there is a lock in the lock pool vPutBackKey(semi); }else{ printf("fork error!\\ "); } return 0; } 65,1 Bottom
The operation effect is as follows: (Because there is no key for initialization, the parent process does not get the key, the child process runs first, then puts the key in, and the parent process gets the key and then runs)