semaphore & ipc_message posix message queue & ipc_shared Memory

本文介绍了信号量(semaphore)的内部实现原理,包括用户级和内核级的区别,以及如何通过SEM_UNDO标志实现进程异常终止时信号量的回滚。此外,还探讨了POSIX消息队列和IPC消息的实现机制,以及共享内存(shmid_kernel)的管理方式。

semaphore

每个semaphore用一个sem_array来代表,每个sem_array里包含一个或者多个sem结构,sem代表一个原子信号量,用户使用的semaphore跟内核使用的semaphore有个很大的区别在于,用户的semaphore可以包含多个信号值,每个信号值用sem来代表。如果进程使用semop()操作时带上了SEM_UNDO标志,那么进程对信号量的操作将会被一个sem_undo结构记录,这样当进程因为错误而终止时,系统可以使用sem_undo结构将信号量的值恢复到进程未使用的状态。

ipc_message & posix message queue

每个message用一个msg_queue结构来进行代表,queue里的信息使用msg_msg来表示。posix message queue的实现方式跟ipc_message(system v)是不同的,它使用一个特殊文件系统mqueue来实现的,这个文件系统可以被挂载到文件系统中。每个队列使用一个mqueue_inode_info来表示的,它跟一个mqueue文件系统的inode进行关联,也是通过address_space使用page cache来使用内存的。

ipc_sharedMemory

一个共享的内存用一个shmid_kernel结构来进行表示,它里面有个field指向file结构,file指向shm特殊文件系统的inode结构,共享的内存page frame使用的是page cache,通过address_space结构跟inode进行关联。这样的做的原因有2点:

1.可以使用vfs系统接口,也就是文件操作接口来进行操作

2.可以利用vfs的实现结构,从而实现代码重用

// 主进程 static void process_A(int shared_memory_id, int message_queue_id, int semaphore_id) { shm_data *shared_memory = (shm_data *)shmat(shared_memory_id, NULL, 0); msg_form message; size_t total_data_sent = 0; int send_count = 0; // 发送轮次 time_t start_time = time(NULL); if ((void *)-1 == shared_memory) { perror("shmat failed"); exit(EXIT_FAILURE); } printf("A: 启动成功\n"); fflush(stdout); while (send_count < 2) { char message_data[MAX_DATA_SIZE]; // 存放发送的数据内容 size_t data_size = snprintf(message_data, MAX_DATA_SIZE, "i will send some message to B: count: %d", send_count); shm_data send_data = { .length = data_size, .crc32 = crc32(message_data, data_size), }; memcpy(send_data.data, message_data, data_size); // 进入临界区获取信号量 P_semaphore(semaphore_id); memcpy(shared_memory, &send_data, sizeof(shm_data)); V_semaphore(semaphore_id); // 构造发送给B的消息 message.msg_type = MSG_SENT_A_TO_B; message.msg_text[0] = '1'; message.msg_text[1] = '\0'; msgsnd(message_queue_id, &message, strlen(message.msg_text) + 1, 0); // 接收 B 的响应消息 msgrcv(message_queue_id, &message, MAX_MSG_SIZE, MSG_ANSWER_B_TO_A, 0); int b_response = atoi(message.msg_text); time_t now = time(NULL); printf("[%ld] A: 发送了 %zu 字节数据给 B, 校验 %s\n", now - start_time, data_size, b_response ? "正确" : "错误"); total_data_sent += data_size; send_count++; sleep(1); // 等待一秒 } printf("A: 总共发送数据大小为: %zu 字节\n", total_data_sent); shmdt(shared_memory); } // 子进程 static void process_B(int shared_memory_id, int message_queue_id, int semaphore_id) { shm_data *shared_memory = (shm_data *)shmat(shared_memory_id, NULL, 0); msg_form message; size_t total_data_received = 0; time_t start_time = time(NULL); if ((void *)-1 == shared_memory) { perror("shmat"); exit(EXIT_FAILURE); } printf("B: 启动成功\n"); fflush(stdout); while (1) { msgrcv(message_queue_id, &message, MAX_MSG_SIZE, MSG_SENT_A_TO_B, 0); shm_data received_data; // 进入临界区获取信号量 P_semaphore(semaphore_id); memcpy(&received_data, shared_memory, sizeof(shm_data)); V_semaphore(semaphore_id); uint32_t actual_crc = crc32(received_data.data, received_data.length); int result = (actual_crc == received_data.crc32); time_t current_time = time(NULL); printf("[%ld] B: 接收了 %zu 字节数据,校验 %s\n", current_time - start_time, received_data.length, result ? "正确" : "错误"); total_data_received += received_data.length; message.msg_type = MSG_ANSWER_B_TO_A; snprintf(message.msg_text, MAX_MSG_SIZE, "%d", result); msgsnd(message_queue_id, &message, strlen(message.msg_text) + 1, 0); } printf("B: 总共接收数据大小为: %zu 字节\n", total_data_received); shmdt(shared_memory); } int main() { int shared_memory_id, message_queue_id, semaphore_id; init_ipc(&shared_memory_id, &message_queue_id, &semaphore_id); pid_t child_pid = fork(); if (child_pid < 0) { perror("fork"); exit(EXIT_FAILURE); } else if (0 == child_pid) { // 子进程运行 B process_B(shared_memory_id, message_queue_id, semaphore_id); } else { // 父进程运行 A process_A(shared_memory_id, message_queue_id, semaphore_id); wait(NULL); // 等待子进程结束 // 父进程使用 shmctl、msgctl 和 semctl 删除共享内存段、消息队列和信号量 shmctl(shared_memory_id, IPC_RMID, NULL); msgctl(message_queue_id, IPC_RMID, NULL); semctl(semaphore_id, 0, IPC_RMID); } return 0; }帮我根据这个写一个设计文档
最新发布
08-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值