使用semop在两个进程中实现共享内存读写的同步
时间: 2024-02-01 14:13:39 浏览: 79
可以通过使用信号量来实现在两个进程中共享内存读写的同步。下面是一个示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define SEM_KEY 1234
#define SHM_KEY 5678
int main() {
int semid, shmid;
struct sembuf p = {0, -1, SEM_UNDO}; // P操作
struct sembuf v = {0, 1, SEM_UNDO}; // V操作
// 创建信号量
if ((semid = semget(SEM_KEY, 1, IPC_CREAT | 0666)) == -1) {
perror("semget");
exit(1);
}
// 初始化信号量,初值为1
if (semctl(semid, 0, SETVAL, 1) == -1) {
perror("semctl");
exit(1);
}
// 创建共享内存
if ((shmid = shmget(SHM_KEY, sizeof(int), IPC_CREAT | 0666)) == -1) {
perror("shmget");
exit(1);
}
// 将共享内存映射到当前进程的地址空间中
int *shm_ptr;
if ((shm_ptr = (int *) shmat(shmid, 0, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
pid_t pid;
if ((pid = fork()) == -1) {
perror("fork");
exit(1);
} else if (pid == 0) { // 子进程写共享内存
int i;
for (i = 1; i <= 10; i++) {
semop(semid, &p, 1); // P操作,获取信号量
*shm_ptr = i; // 写共享内存
printf("子进程写入 %d\n", i);
semop(semid, &v, 1); // V操作,释放信号量
sleep(1);
}
exit(0);
} else { // 父进程读共享内存
int i;
for (i = 1; i <= 10; i++) {
semop(semid, &p, 1); // P操作,获取信号量
printf("父进程读取 %d\n", *shm_ptr); // 读共享内存
semop(semid, &v, 1); // V操作,释放信号量
sleep(1);
}
wait(NULL);
}
// 解除共享内存的映射
if (shmdt(shm_ptr) == -1) {
perror("shmdt");
exit(1);
}
// 删除共享内存
if (shmctl(shmid, IPC_RMID, NULL) == -1) {
perror("shmctl");
exit(1);
}
// 删除信号量
if (semctl(semid, 0, IPC_RMID, 0) == -1) {
perror("semctl");
exit(1);
}
return 0;
}
```
在上述代码中,我们首先创建了一个信号量和一个共享内存,然后使用fork()创建了一个子进程和一个父进程。子进程负责写共享内存,父进程负责读共享内存。在读写共享内存之前,我们使用semop()函数对信号量进行P操作和V操作,以保证读写的同步性。当子进程写完共享内存后,它会通过sleep()函数暂停1秒钟,然后继续写下一个数。当父进程读取完共享内存后,它也会通过sleep()函数暂停1秒钟,然后继续读取下一个数。
需要注意的是,在使用semop()函数进行P操作和V操作时,第三个参数应该设置为1,表示只操作一个信号量。并且在进行P操作和V操作之前,需要定义一个sembuf结构体,并将其作为semop()函数的第二个参数传入。其中,sembuf结构体包含三个字段:sem_num表示要操作的信号量的编号,通常为0;sem_op表示要进行的操作,-1表示P操作,1表示V操作;sem_flg表示操作标志,通常为SEM_UNDO。
在代码末尾,我们需要先使用shmdt()函数解除共享内存的映射,然后使用shmctl()函数删除共享内存。最后使用semctl()函数删除信号量。
阅读全文