原理:
Send进程通过建立共享内存区域,并向其中写入数据,Recive通过与共享内存连接读取其中的数据。
但是如果进程进行读取操作的时候其他进程再次写入会产生数据丢失,产生竞态,为了确保在某段时间内只有一个操作,即读操作或者写操作,所以引入同步互斥机制,对每个信号量的操作为PV操作。
代码:
SemaphoreSend.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
#include <string.h>
#define N 128
struct shmbuf{
char buf[N];
};
union semun{
int val;
};
int main(){
key_t key;
if((key = ftok(".", 'q')) < 0){ // 创建标识符
perror("ftok error");
return -1;
}
int shmid;
struct shmbuf *shm;
if((shmid = shmget(key, 512, IPC_CREAT|IPC_EXCL|0664)) < 0){ // 创建一块虚拟内存
if(errno != EEXIST){
perror("shmget error");
return -1;
}
else{
shmid = shmget(key, 512, 0664);
}
}
if((shm = shmat(shmid, NULL, 0)) > 0){ //在进程虚拟地址空间选择一块做共享内存,此区域可读可写
printf("shm:%p\n", shm);
}
int semid;
union semun semun;
struct sembuf sem;
semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0664); // 创建信号量集合,内部设置两个信号量
if(semid < 0){ // 创建错误要么有问题要么集合已经存在
if(errno != EEXIST){
perror("semget error");
return -1;
}
else{
semid = semget(key, 2, 0664);
}
}
else{ // 初始化信号量的值
semun.val = 0;
semctl(semid, 0, SETVAL, semun); // 设置第一个信号量的值为0
semun.val = 1;
semctl(semid, 1, SETVAL, semun); // 设置第二个信号量的值为1
}
while(1){
sem.sem_num = 1;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid, &sem, 1); // 获取写权限
fgets(shm->buf, N, stdin); // 向控制台获取数据写入共享内存,且指针指向用户输入
shm->buf[strlen(shm->buf) - 1] = '\0'; // 将换行符号变成'\0'
sem.sem_num = 0;
sem.sem_op = 1;
sem.sem_flg = 0; // 释放读权限
semop(semid, &sem, 1);
if(strncmp(shm->buf, "quit", 4) == 0){
shmdt(shm); // 断开虚拟内存
break;
}
}
return 0;
}
SemaphoreRecive.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
#include <string.h>
#define N 128
struct shmbuf{
char buf[N];
};
union semun{
int val;
};
int main(){
key_t key;
if((key = ftok(".", 'q')) < 0){ // 创建标识符
perror("ftok error");
return -1;
}
int shmid;
struct shmbuf *shm;
if((shmid = shmget(key, 512, IPC_CREAT|IPC_EXCL|0664)) < 0){ // 创建一块虚拟内存
if(errno != EEXIST){
perror("shmget error");
return -1;
}
else{
shmid = shmget(key, 512, 0664);
}
}
if((shm = shmat(shmid, NULL, 0)) > 0){ //在进程虚拟地址空间选择一块做共享内存,此区域可读可写
printf("shm:%p\n", shm);
}
int semid;
union semun semun;
struct sembuf sem;
semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0664); // 创建信号量集合,内部设置两个信号量
if(semid < 0){ // 创建错误要么有问题要么集合已经存在
if(errno != EEXIST){
perror("semget error");
return -1;
}
else{
semid = semget(key, 2, 0664);
}
}
else{ // 初始化信号量的值
semun.val = 0;
semctl(semid, 0, SETVAL, semun); // 设置第一个信号量的值为0
semun.val = 1;
semctl(semid, 1, SETVAL, semun); // 设置第二个信号量的值为1
}
while(1){
sem.sem_num = 0;
sem.sem_op = -1;
sem.sem_flg = 0; // 申请读权限
semop(semid, &sem, 1);
if(strncmp(shm->buf, "quit", 4) == 0){
shmdt(shm); // 断开共享内存
shmctl(shmid, IPC_RMID, NULL); // 删除共享内存断
semctl(semid, 0, IPC_RMID, NULL);
semctl(semid, 1, IPC_RMID< NULL); // 删除信号量,删除信号集
break;
}
printf("buf:%s\n", shm->buf);
sem.sem_num = 1;
sem.sem_op = 1;
sem.sem_flg = 0; // 释放写权限
semop(semid, &sem, 1);
}
return 0;
}
开启两个端口,分别运行Send和Recive程序