本文共 3836 字,大约阅读时间需要 12 分钟。
进程是一个独立的资源管理单元,不同进程之间的资源是隔离的,无法直接访问彼此的内存空间。但是,进程之间需要通过某种方式进行信息交互和状态传递,这就要求操作系统提供进程间通信和同步的机制。在Linux系统中,进程间通信主要通过以下几种方式实现:同主机进程间的信息交互、同主机进程间的同步机制、同主机进程间的异步机制,以及网络主机间的数据交互。
共享内存是一种进程间通信的机制,主要用于实现进程间大块数据的传递。通过共享内存,多个进程可以直接访问同一块内存区域,但需要通过操作系统进行协调和管理。
共享内存的内存结构通常由操作系统管理,具体实现可能依赖于系统的内核类型(比如是不安全共享内存还是安全共享内存)。在Linux系统中,共享内存主要用于进程间的数据交互,通常需要通过特定的系统调用函数来进行操作。
共享内存的数据结构在Linux系统中通常由struct shmid_ds
表示,这个结构包含了共享内存段的各种属性信息,如段的大小、创建进程的PID、最后一个操作进程的PID等。
shmget
是创建共享内存段的重要系统调用函数。它的作用是为进程分配一段共享内存空间,可以由其他进程访问。以下是 shmget
的关键参数和功能:
ftok
函数生成的键值,用于标识共享内存段。shmget
返回的值是一个标识符(shmid
),表示共享内存段的唯一标识。如果共享内存段不存在,则函数会创建一个新的段;如果已存在,则返回段的首地址。
shmctl
是管理共享内存段的系统调用函数,主要用于对共享内存段的状态进行操作。它支持以下几种操作:
shmctl
的命令参数(cmd
)决定了具体的操作类型,常见的命令包括:
IPC_RMID
:删除共享内存段。IPC_SET
:设置共享内存段的访问权限和属性。IPC_STAT
:获取共享内存段的访问权限和属性。shmat
是将共享内存段挂载到进程地址空间的函数。它的作用是为当前进程分配一个虚拟地址,指向共享内存段。使用 shmat
后,进程可以通过这个虚拟地址直接访问共享内存内容。
shmat
的返回值是一个指针,指向共享内存段的首地址。如果函数成功,返回的指针不为 NULL
;如果失败,返回 NULL
或负值。
shmdt
是将进程与共享内存段的挂载关系解除的函数。它的作用是通知操作系统,当前进程不再使用该共享内存段,但并不删除共享内存段本身。
以下是两个进程通过共享内存进行数据交互的示例代码:
#include#include #include #include #include #include #include #include int main(int argc, char *argv[]) { key_t key; int shm_id; int sem_id; int value = 0; // 生成共享内存键 key = ftok(".", 0xFF); // 创建信号量 sem_id = semget(key, 1, IPC_CREAT | 0644); if (-1 == sem_id) { perror("semget"); exit(EXIT_FAILURE); } // 初始化信号量为0 if (-1 == semctl(sem_id, 0, SETVAL, value)) { perror("semctl"); exit(EXIT_FAILURE); } // 创建共享内存段(1KB) shm_id = shmget(key, 1024, IPC_CREAT | 0644); if (-1 == shm_id) { perror("shmget"); exit(EXIT_FAILURE); } // 将共享内存段挂载到进程 char *shm_ptr = shmat(shm_id, NULL, 0); if (NULL == shm_ptr) { perror("shmat"); exit(EXIT_FAILURE); } // 进行消息传输 struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_flg = SEM_UNDO; sem_b.sem_op = 1; while (1) { if (0 == (value = semctl(sem_id, 0, GETVAL))) { printf("\n现在,发送过程在运行:\n"); printf("\t输入发送的消息: "); scanf("%s", shm_ptr); if (-1 == semop(sem_id, &sem_b, 1)) { perror("semop"); exit(EXIT_FAILURE); } } // 如果输入“end”,退出发送过程 if (0 == strcmp(shm_ptr, "end")) { printf("\n退出发送过程现在!\n"); break; } } // 分离进程与共享内存 shmdt(shm_ptr); return 0;}
#include#include #include #include #include #include #include #include int main(int argc, char *argv[]) { key_t key; int shm_id; int sem_id; int value = 0; // 生成共享内存键 key = ftok(".", 0xFF); // 创建信号量 sem_id = semget(key, 1, IPC_CREAT | 0644); if (-1 == sem_id) { perror("semget"); exit(EXIT_FAILURE); } // 初始化信号量为0 if (-1 == semctl(sem_id, 0, SETVAL, value)) { perror("semctl"); exit(EXIT_FAILURE); } // 创建共享内存段(1KB) shm_id = shmget(key, 1024, IPC_CREAT | 0644); if (-1 == shm_id) { perror("shmget"); exit(EXIT_FAILURE); } // 将共享内存段挂载到进程 char *shm_ptr = shmat(shm_id, NULL, 0); if (NULL == shm_ptr) { perror("shmat"); exit(EXIT_FAILURE); } // 进行消息接收 struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_flg = SEM_UNDO; sem_b.sem_op = -1; while (1) { if (1 == (value = semctl(sem_id, 0, GETVAL))) { printf("\n现在,接收过程在运行:\n"); printf("\t接收到的消息是: %s\n", shm_ptr); if (-1 == semop(sem_id, &sem_b, 1)) { perror("semop"); exit(EXIT_FAILURE); } } // 如果输入“end”,退出接收过程 if (0 == strcmp(shm_ptr, "end")) { printf("\n退出接收过程现在!\n"); break; } } // 分离进程与共享内存 shmdt(shm_ptr); // 删除共享内存段 if (-1 == shmctl(shm_id, IPC_RMID, NULL)) { perror("shmctl"); exit(EXIT_FAILURE); } // 删除信号量 if (-1 == semctl(sem_id, 0, IPC_RMID)) { perror("semctl"); exit(EXIT_FAILURE); } return 0;}
以上代码展示了两个进程之间通过共享内存进行消息传输的过程。通过信号量的管理,确保了共享内存段的互斥访问,避免了竞争条件,从而保证了数据的正确传递。
转载地址:http://kekfk.baihongyu.com/