10.共享内存 信号量集 消息队列
- **1. IPC对象操作通用框架**
- **2. 共享内存(Shared Memory)**
- **3. 信号量集(Semaphore)**
- **4. 消息队列(Message Queue)**
- **5. 练习与作业**
- **6. 总结**
1. IPC对象操作通用框架
- 操作流程:
- 生成唯一键值(
ftok
):key_t ftok(const char *pathname, int proj_id);
- 功能:通过路径和项目ID生成唯一键值。
- 参数:
pathname
:文件路径。proj_id
:项目ID(通常为ASCII字符)。
- 返回值:成功返回键值,失败返回
-1
。
- 申请IPC对象:
- 共享内存:
shmget
。 - 信号量集:
semget
。 - 消息队列:
msgget
。
- 共享内存:
- 操作IPC对象:
- 共享内存:
shmat
、shmdt
。 - 信号量集:
semop
。 - 消息队列:
msgsnd
、msgrcv
。
- 共享内存:
- 删除IPC对象:
- 共享内存:
shmctl
。 - 信号量集:
semctl
。 - 消息队列:
msgctl
。
- 共享内存:
- 生成唯一键值(
2. 共享内存(Shared Memory)
- 特性:
- 效率最高的进程间通信方式。
- 多个进程可以共享同一块内存区域。
- 操作流程:
- 申请共享内存:
int shmget(key_t key, size_t size, int shmflg);
- 功能:申请共享内存。
- 参数:
key
:唯一键值。size
:共享内存大小。shmflg
:权限标志(如IPC_CREAT|0666
)。
- 返回值:成功返回共享内存ID,失败返回
-1
。
- 映射共享内存:
void *shmat(int shmid, const void *shmaddr, int shmflg);
- 功能:将共享内存映射到进程地址空间。
- 参数:
shmid
:共享内存ID。shmaddr
:映射地址(通常为NULL
,由系统分配)。shmflg
:映射标志(如0
表示读写,SHM_RDONLY
表示只读)。
- 返回值:成功返回映射地址,失败返回
(void*)-1
。
- 读写共享内存:
- 使用
memcpy
、strcpy
等函数直接操作映射地址。
- 使用
- 撤销映射:
int shmdt(const void *shmaddr);
- 功能:断开共享内存映射。
- 参数:
shmaddr
:映射地址。 - 返回值:成功返回
0
,失败返回-1
。
- 删除共享内存:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 功能:删除共享内存。
- 参数:
shmid
:共享内存ID。cmd
:命令(如IPC_RMID
表示删除)。buf
:共享内存信息结构体(通常为NULL
)。
- 返回值:成功返回
0
,失败返回-1
。
- 申请共享内存:
3. 信号量集(Semaphore)
- 特性:
- 用于解决共享内存的临界资源访问问题。
- 通过P(
sem_wait
)和V(sem_post
)操作实现同步。
- 操作流程:
- 申请信号量集:
int semget(key_t key, int nsems, int semflg);
- 功能:申请信号量集。
- 参数:
key
:唯一键值。nsems
:信号量数量。semflg
:权限标志(如IPC_CREAT|0666
)。
- 返回值:成功返回信号量集ID,失败返回
-1
。
- 初始化信号量:
- 使用
semctl
初始化信号量值。
- 使用
- P/V操作:
int semop(int semid, struct sembuf *sops, unsigned nsops);
- 功能:执行P/V操作。
- 参数:
semid
:信号量集ID。sops
:操作结构体数组。nsops
:操作数量。
- 返回值:成功返回
0
,失败返回-1
。
- 删除信号量集:
int semctl(int semid, int semnum, int cmd, ...);
- 功能:删除信号量集。
- 参数:
semid
:信号量集ID。semnum
:信号量编号。cmd
:命令(如IPC_RMID
表示删除)。
- 返回值:成功返回
0
,失败返回-1
。
- 申请信号量集:
4. 消息队列(Message Queue)
- 特性:
- 用于进程间传递消息。
- 消息以队列形式存储,先进先出(FIFO)。
- 操作流程:
- 申请消息队列:
int msgget(key_t key, int msgflg);
- 功能:申请消息队列。
- 参数:
key
:唯一键值。msgflg
:权限标志(如IPC_CREAT|0666
)。
- 返回值:成功返回消息队列ID,失败返回
-1
。
- 发送消息:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- 功能:发送消息。
- 参数:
msqid
:消息队列ID。msgp
:消息结构体指针。msgsz
:消息大小。msgflg
:发送标志(如0
表示阻塞)。
- 返回值:成功返回
0
,失败返回-1
。
- 接收消息:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
- 功能:接收消息。
- 参数:
msqid
:消息队列ID。msgp
:消息结构体指针。msgsz
:消息大小。msgtyp
:消息类型。msgflg
:接收标志(如0
表示阻塞)。
- 返回值:成功返回消息大小,失败返回
-1
。
- 删除消息队列:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
- 功能:删除消息队列。
- 参数:
msqid
:消息队列ID。cmd
:命令(如IPC_RMID
表示删除)。buf
:消息队列信息结构体(通常为NULL
)。
- 返回值:成功返回
0
,失败返回-1
。
- 申请消息队列:
5. 练习与作业
- 练习1:使用共享内存完成两个进程间的通信,共享一个数字。
- 练习2:设计两个进程,进程1获取用户输入并写入共享内存,进程2读取共享内存并打印输出,遇到
exit
时退出。 - 作业1:封装信号量的P/V操作函数:
int my_sem_wait(int id, int sem); int my_sem_post(int id, int sem);
- 作业2:使用信号量集解决共享内存的临界资源访问问题。
6. 总结
- 共享内存:效率最高的IPC方式,适合大数据量传输。
- 信号量集:用于解决共享内存的同步问题。
- 消息队列:适合进程间传递结构化消息。