进程间通信下IPC总共五种分别是管道、信号量、消息队列、共享内存、套接字使用ipcs可以看到Linux下存在的IPCipcrm -mshmid 删除指定共享内存ipcrm -ssemid 删除指定信号量ipcrm -qmsqid 删除指定消息队列3.共享内存共享内存允许多个进程共享同一块物理内存区域。这意味着一个进程写入共享内存的数据其他进程可以立即看到不需要内核在进程间复制数据这是它快的主要原因进程可以直接读写内存就像操作普通内存一样零拷贝、速度快、容量大共享内存函数#include sys/shm.h int shmget(key_t key, size_t size, int shmflg);参数key_t key共享内存段的键值跟信号量的semget()参数非常像不是吗参数size_t size共享内存的内存大小信号量这里是信号量个数参数int shmflg权限和创作标志依旧和信号量一模一样权限位与文件权限类似0600创建选项IPC_CREAT如果不存在则创建如果已存在则忽略IPC_EXCL与IPC_CREAT一起使用如果已存在则失败返回值创建成功返回共享内存的标识符非负整数失败返回-1共享内存的shmget()函数和信号量的semget()相似程度极高结合起来进行记忆void *shmat(int shmid, const void *shmaddr, int shmflg);参数int shmidshmget()返回的共享内存标识符参数const void* shmaddr指定附加地址通常填NULL就行参数int shmflg附加标志填0就行感觉有点故弄玄乎返回值成功返回共享内存段在进程地址空间中的起始地址失败返回(void*)-1这个函数理解成将共享内存的地址映射过来的作用就行填写参数也非常简单int shmdt(const void *s);非常简单的函数作用是当前进程失去对这块共享内存的控制即解除映射参数const void* s共享内存段在进程地址空间中的起始地址函数shmat()的返回值int shmctl(int shmid, int cmd, struct shmid_ds *buf);参数int shmid同上共享内存标识符参数int cmd控制命令IPC_RMID标记删除共享内存段当所有进程都分离后真正删除IPC_STAT获取共享内存状态信息IPC_SET设置共享内存参数参数struct shmid_ds* buf指向状态结构的指针我才发现老师疏忽了这个函数...这个是啥意思我也不懂捏下面通过一段简单的代码演示共享内存的用法此时通过a进程往共享内存中写入了一句helloa进程结束后并没有调用shmctl()函数所以这块共享内存依旧存在。注第一个参数的键值必须相同才能指向同一片空间而因为当前空间已经被创建所以后面两个参数填多少都已经无所谓了。此时b进程也映射了这块共享内存可以对里面的内容进行访问了。此时对a进程和b进程进行编写可以得到共享内存的数据。但是此时存在一个问题我们若是先运行b此时共享内存中还什么内容都没有写入则b进程是读取不到内容的或是读取到随机值那么就必须控制b进程在a进程之后才能读取共享内存有什么办法可以做到呢很容易便可以想到通过信号量的pv操作来控制进程的先后让a进程写一次b进程就可以读取一次。那么此时就会引发第二个问题我们需要几个信号量信号量的初值pv操作该放到哪里毫无疑问我们需要两个信号量s1和s2其中s1控制a进程是否往共享内存中写入数据所以初值为1即一开始就可以写入数据而s2控制b进程能否读取共享内存中的数据所以初值为0即一开始共享内存无数据所以不能进行读取。如图所示s1先进行p操作减为0此时写入数据然后对s2进行v操作1则此时b进程不会再被阻塞住读出数据后再对s1进行v操作使得s1恢复到初值循环成立。sem.c的代码为#include sem.hint semid -1;void sem_init()//创建两个信号量或 获取id{semid semget((key_t)1234,2,IPC_CREAT|IPC_EXCL|0600);//全新创建已存在则失败if( semid -1 ){semid semget((key_t)1234,2,0600);//获取if( semid -1 ){printf(semget err\n);}}else{union semun a;int arr[2] {1,0};for(int i 0; i 2; i){a.val arr[i];if( semctl(semid,i,SETVAL,a) -1 ){printf(semctl setval err\n);}}}}void sem_p(enum SEMID index){struct sembuf buf;buf.sem_num index;buf.sem_op -1;//pbuf.sem_flg SEM_UNDO;if( semop(semid,buf,1) -1 ){printf(p err\n);}}void sem_v(enum SEMID index){struct sembuf buf;buf.sem_num index;buf.sem_op 1;//vbuf.sem_flg SEM_UNDO;if( semop(semid,buf,1) -1 ){printf(v err\n);}}void sem_destroy(){if( semctl(semid,0,IPC_RMID) -1 ){printf(destroy err\n);}}最好自己实现一遍会更好理解代码本身也不难主要还是记忆a.c与b.c的代码(仅展示与之前不同的地方)a.c b.c至此通过信号量来控制a进程写入一句话b进程才能读取一段话的程序便设计完成了通过编译运行来看看结果当输入end时a进程和b进程同时结束。4.消息队列一种异步通信机制用于在分布式系统中传递消息。它允许不同的应用程序或服务通过发送和接收消息来进行通信而无需彼此直接连接或同时在线。消息队列函数消息队列要求消息结构必须包含一个 long 类型的消息类型字段// 基本消息结构 struct msgbuf { long mtype; // 消息类型必须 0 char buff[32]; // 消息数据可以是任意类型 };#include sys/msg.h int msgget(key_t key, int msgflg);参数key_t key消息队列的键值依旧键值和前面的相似参数int msgflg权限标志权限位与文件权限类似0600创建选项IPC_CREAT如果不存在则创建如果已存在则忽略IPC_EXCL与IPC_CREAT一起使用如果已存在则失败返回值消息队列标识符和信号量以及共享内存很像就是少了一个参数int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);发送消息参数int msqid消息队列标识符依旧msgget()返回值参数const void* msgp指向消息缓冲区的指针即基本消息结构体的指针参数size_t msgsz消息数据的长度上面结构体中sizeof(buff)的大小参数int msgflg发送标志一般填0即可返回值成功为0失败-1。ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);接收消息参数int msqid消息队列标识符依旧msgget()返回值参数const void* msgp指向消息缓冲区的指针即基本消息结构体的指针参数size_t msgsz消息数据的长度上面结构体中sizeof(buff)的大小参数long msgtyp,接收指定的消息类型上面结构体中的mtype对应若是0则接收所有消息0则接收mtype最小的消息参数int msgflg发送标志一般填0即可int msgctl(int msqid, int cmd, struct msqid_ds *buf);控制消息队列参数int msqid消息队列标识符依旧msgget()返回值参数int cmd控制命令常用命令IPC_RMID立即删除消息队列IPC_STAT获取消息队列状态信息IPC_SET设置消息队列参数IPC_INFO获取系统消息队列限制信息Linux 特有MSG_INFO获取消息队列资源使用情况Linux 特有参数 struct msqid_ds* buf指向状态结构的指针返回值成功为0失败-1。演示代码发送消息 接收消息个人小结IPC这块感觉很难记啊不过好在自己编了一次代码之后理解倒是深了一部分不过感觉还是差得远啊后面就到线程了这块还是要不断复习牢固记忆。