实现两个进程一边输入,一边输出,输入quit时结束。
/*
通过信号灯集与共享内存配合,实现输入输出交替进行,做到输入一个输出一个
(1)初始化:零号信号灯初值为0,一号信号灯初值为1
(2)输入部分:申请一号信号灯,可以申请到资源,然后一号信号灯变为0,
输入完成之后,释放零号信号灯,零号信号灯就变为1;
(3)输出部分:申请零号信号灯,刚开始零号信号灯初值为0,无法申请到资源,
只有当输入进程完成输入,把零号信号灯变为1之后,输出进程才可以申请到资源,进行输出,
输入完成之后,释放一号信号灯,让一号信号灯变为1,然后输入进程可以申请资源继续输入
*/
第一部分:输入
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
/*
通过信号灯集与共享内存配合,实现输入输出交替进行,做到输入一个输出一个
(1)初始化:零号信号灯初值为0,一号信号灯初值为1
(2)输入部分:申请一号信号灯,可以申请到资源,然后一号信号灯变为0,
输入完成之后,释放零号信号灯,零号信号灯就变为1;
(3)输出部分:申请零号信号灯,刚开始零号信号灯初值为0,无法申请到资源,
只有当输入进程完成输入,把零号信号灯变为1之后,输出进程才可以申请到资源,进行输出,
输入完成之后,释放一号信号灯,让一号信号灯变为1,然后输入进程可以申请资源继续输入
*/
union semun
{
int val;
};
// 初始化信号灯集
void init(int semid, int num, int val)
{
union semun sem;
sem.val = val; // 初始化的值
semctl(semid, num, SETVAL, sem); // 对编号为num的信号灯初始化为 sem
}
// 信号灯集操作
void pv(int semid, int num, int op)
{
struct sembuf mysembuf;
mysembuf.sem_num = num; // 进行操作的信号灯编号
mysembuf.sem_op = op; // pv操作
mysembuf.sem_flg = 0;
semop(semid, &mysembuf, 1);
}
int main(int argc, char const *argv[])
{
// 定义信号灯集id与共享内存id
int shmid;
int semid;
// 创建key值
key_t key;
key = ftok("semsharein.c", 'd');
if (key < 0)
{
perror("key error");
return -1;
}
printf("key:%#x\n", key);
// 创建或打开信号灯集
// 不存在创建,存在返回-1
semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0777);
if (semid <= 0)
{
if (errno == EEXIST) // 如果存在,直接打开,返回id
{
semid = semget(key, 2, 0777);
}
else
{
perror("semid error");
return -1;
}
}
else
{
// 初始化信号灯集
// 若是信号灯集已经被创建,则直接打开,无需重新初始化
init(semid, 0, 0);
init(semid, 1, 1);
}
printf("semid:%d\n", semid);
// 获取信号灯值
printf("%d\n", semctl(semid, 0, GETVAL));
printf("%d\n", semctl(semid, 1, GETVAL));
// 创建或打开共享内存
// 不存在创建,存在返回-1
shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777);
// 如果存在,直接打开,返回id
if (shmid <= 0)
{
if (errno == EEXIST)
{
shmid = shmget(key, 128, 0777);
}
else
{
perror("shmid error");
return -1;
}
}
printf("shmid:%d\n", shmid);
// 映射共享内存
char *p;
p = (char *)shmat(shmid, NULL, 0);
if (p == (char *)-1)
{
perror("shmat err");
return -1;
}
// 循环向共享内存中写入内容
while (1)
{
// 申请信号灯序号为1的资源,有就申请,没有就阻塞等待
pv(semid, 1, -1);
scanf("%s", p);
// 释放信号灯序号为0的资源
pv(semid, 0, 1);
if (strcmp(p, "quit") == 0)
{
break;
}
}
// 取消映射
shmdt(p);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
// 删除信号灯集
semctl(semid, 0, IPC_RMID);
return 0;
}
第二部分:输出
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
union semun
{
int val;
};
// 初始化信号灯集
void init(int semid, int num, int val)
{
union semun sem;
sem.val = val; // 初始化的值
semctl(semid, num, SETVAL, sem); // 对编号为num的信号灯初始化为 sem
}
// 信号灯集操作
void pv(int semid, int num, int op)
{
struct sembuf mysembuf;
mysembuf.sem_num = num; // 进行操作的信号灯编号
mysembuf.sem_op = op; // pv操作
mysembuf.sem_flg = 0;
semop(semid, &mysembuf, 1);
}
int main(int argc, char const *argv[])
{
int shmid;
int semid;
// 创建key值
key_t key;
key = ftok("semsharein.c", 'd');
if (key < 0)
{
perror("key error");
return -1;
}
printf("key:%#x\n", key);
// 创建或打开信号灯集
// 不存在创建,存在返回-1
semid = semget(key, 2, IPC_CREAT | IPC_EXCL | 0777);
if (semid <= 0)
{
if (errno == EEXIST) // 如果存在,直接打开,返回id
{
semid = semget(key, 2, 0777);
}
else
{
perror("semid error");
return -1;
}
}
else
{
// 初始化信号灯集
// 若是信号灯集已经被创建,则直接打开,无需重新初始化
init(semid, 0, 0);
init(semid, 1, 1);
}
printf("semid:%d\n", semid);
// 获取信号灯值
printf("%d\n", semctl(semid, 0, GETVAL));
printf("%d\n", semctl(semid, 1, GETVAL));
// 创建或打开共享内存
// 不存在创建,存在返回-1
shmid = shmget(key, 128, IPC_CREAT | IPC_EXCL | 0777);
// 如果存在,直接打开,返回id
if (shmid <= 0)
{
if (errno == EEXIST)
{
shmid = shmget(key, 128, 0777);
}
else
{
perror("shmid error");
return -1;
}
}
printf("shmid:%d\n", shmid);
// 映射共享内存
char *p;
p = (char *)shmat(shmid, NULL, 0);
if (p == (char *)-1)
{
perror("shmat err");
return -1;
}
// 循环读取共享内存中的内容
while (1)
{
if (strcmp(p, "quit") == 0)
{
break;
}
// 申请信号灯序号为0的资源,有就申请,没有就阻塞等待
pv(semid, 0, -1);
printf("%s\n", p);
// 释放信号灯序号为0的资源
pv(semid, 1, 1);
}
// 取消映射
shmdt(p);
// 删除共享内存
shmctl(shmid, IPC_RMID, NULL);
// 删除信号灯集
semctl(semid, 0, IPC_RMID);
return 0;
}
运行效果