comm.c
#include "comm.h" static int commShm(int size, int flags) { key_t key = ftok(PATHNAME, PROJ_ID); if (key < 0) { perror("ftok"); return -1; } int shmid = 0; if ((shmid = shmget(_key, size, flags)) < 0) { perror("shmget"); return -2; } return shmid; } int destroyShm(int shmid) { if (shmctl(shmid, IPC_RMID, NULL) < 0) { perror("shmctl"); return -1; } return 0; } int createShm(int size) { return commShm(size, IPC_CREAT | IPC_EXCL | 0666); } int getShm(int size) { return commShm(size, IPC_CREAT); }
server.c
#include "comm.h" int main() { int shmid = createShm(4096); char* addr = shmat(shmid, NULL, 0); sleep(2); int i = 0; while (i++ < 26) { printf("client# %s\n", addr); sleep(1); } shmdt(addr); sleep(2); destroyShm(shmid); return 0; }
client.c
#include "comm.h" int main() { int shmid = getShm(4096); sleep(1); char* addr = shmat(shmid, NULL, 0); sleep(2); int i = 0; while (i < 26) { addr[i] = 'A' + i; i++; addr[i] = 0; sleep(1); } shmdt(addr); sleep(2); return 0; }
结果演示
注意:共享内存没有进行同步与互斥!
特性:
1.最快的进程间通信方式
2.生命周期随内核(并不会随着打开的进程退出而被释放)
注意事项:
共享内存的访问操作存在安全问题(竞争访问出现数据二义问题)
补充:
1.共享内存的本质就是开辟一块物理内存, 让多个进程映射同-块物理内存到自己的地址空间进行访问,实现数据共享的。
2.共享内存的操作是非进程安全的,多个进程同时对共享内存读写是有可能会造成数据的交叉写入或读取,造成数据混乱
3.共享内存的删除操作并非直接删除,而是拒绝后续映射,只有在当前映射链接数为0时,表示没有进程访问了,才会真正被删除
4.共享内存生命周期随内核,只要不删除,就一-直存在于内核中,除非重启系统(当然这里指的是非手动操作,可以手动删除)
消息队列
详细可以参考这篇博客,我这里是简单总结了一下消息队列
功能:实现进程间的数据传输
本质:内核中的一个优先级队列
实现:多个进程通过访问同一一个消息队列,以添加数据节点和获取数据节点实现通信
总结:
1、采用消息队列通信比采用管道通信具有更多的灵活性,通信的进程不但没有血缘上的要求,也不需要进行同步处理。
2、消息队列是一种先进先出的队列型数据结构;
3、消息队列将输出的信息进行了打包处理,可以保证以消息为单位进行接收;
4、消息队列对信息进行分类服务,根据消息的类别进行分别处理。
5、提供消息数据自动拆分功能,同时不能接受两次发送的消息。
6、消息队列提供了不完全随机读取的服务。 7、消息队列提供了完全异步的读写服务。
信号量
(这里做简单介绍)
作用:用于实现进程间的同步与互斥
本质:是一个计数器+ pcb等待队列
P操作:对计数器进行-1操作,判断计数是否大于等于0,正确则返回;失败则阻塞,其中阻塞就是把它置位可中断休眠状态,挂到pcb等待对联中,直到被唤醒
V操作:对计数器进行+ 1操作,若计数器小于等于0,则唤醒一个等待的进程
同步实现:
通过计数器对共享资源进行计数,在获取资源之前,则进行P操作,计数满足访问条件则访问,若不满足则阻塞当产生一个资源,则进行V操作,唤醒阻塞的进程
互斥实现:
初始化计数器为1,表示资源只有一一个。
访问资源之前进行P操作;访问资源完毕之后进行V操作