1. 使用三个程序来完成输出 ABCABCABCABCABC
#include "sem.h"
int main(int argc, const char *argv[])
{
//创建进程
pid_t pid1,pid2;
int semid;
//子进程1
int num = 10;
if((pid1 = fork()) == 0){
//创建信号灯集
semid = create_sem(3);
if(semid == -1){
perror("create_sem1 error");
return -1;
}
while(num--){
p_handle(semid,0);
printf("C");
fflush(stdout);
v_handle(semid,1);
sleep(1);
}
//进程退出
exit(EXIT_SUCCESS);
}else if((pid2 = fork()) == 0){
//创建信号灯集
semid = create_sem(3);
if(semid == -1){
perror("create_sem2 error");
return -1;
}
while(num--){
p_handle(semid,1);
printf("B");
fflush(stdout);
v_handle(semid,2);
sleep(1);
}
exit(EXIT_SUCCESS);
}else {
//创建信号灯集
semid = create_sem(3);
if(semid == -1){
perror("create_sem2 error");
return -1;
}
while(num--){
p_handle(semid,2);
printf("A");
fflush(stdout);
v_handle(semid,0);
sleep(1);
}
}
puts("");
//信号灯删除
del_sem(semid);
wait(NULL);
wait(NULL);
return 0;
}
2. 将共享内存和信号灯集完成两个进程间通信程序重新实现一下
#ifndef _SEM_H__
#define _SEM_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <myhead.h>
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
#define PAGE_SIZE 4096
//信号灯申请,初始化并返回信号灯集id
int create_sem(int semcount);
//申请信号灯资源操作, p 操作
int p_handle(int semid,int semno);
//释放信号灯资源操作 V
int v_handle(int semid,int semno);
//信号灯删除
int del_sem(int semid);
#endif
#include "sem.h"
int init_sem(int semid,int semno){
//输入灯的初始值
int val =-1;
printf("请输入标号%d灯的初始值",semno);
scanf("%d",&val);
//定义共用体并初始化
union semun un;
un.val = val;
if(semctl(semid,semno,SETVAL,un) == -1){
perror("semctl error");
return -1;
}
//成功返回 0
return 0;
}
//信号灯申请,初始化并返回信号灯集id
int create_sem(int semcount){
//1. 创建Key
key_t key = ftok("/",'d');
if(key == -1){
perror("sem ftok error");
return -1;
}
//2.通过key值创建一个信号灯集(这里需要特殊处理下,
//如果存在直接打开,而不需要初始化)
int semid = semget(key,semcount,IPC_CREAT|IPC_EXCL|0664);
if(semid == -1){
if(errno == EEXIST){
semid = semget(key,semcount,IPC_CREAT);
return semid;
}
perror("sem semget error");
return -1;
}
//3. 信号灯初始化(循环初始化)
for(int i=0; i<semcount;i++){
init_sem(semid,i);
}
//4. 返回
return semid;
}
//申请信号灯资源操作, p 操作
int p_handle(int semid,int semno){
//定义结构体变量,并初始化
struct sembuf buf;
//操作几号灯
buf.sem_num = semno;
//申请资源
buf.sem_op = -1;
//没有资源阻塞
buf.sem_flg =0;
if(semop(semid,&buf,1) ==-1){
perror("semop error");
return -1;
}
return 0;
}
//释放信号灯资源操作 V
int v_handle(int semid,int semno){
//定义结构体变量,并初始化
struct sembuf buf;
//操作几号灯
buf.sem_num = semno;
//释放资源
buf.sem_op = 1;
//没有资源阻塞
buf.sem_flg =0;
if(semop(semid,&buf,1) ==-1){
perror("semop error");
return -1;
}
return 0;
}
//信号灯删除
int del_sem(int semid){
//删除
if(semctl(semid,0,IPC_RMID,0) ==-1){
perror("del_sem semctl error");
return -1;
}
return 0;
}
#include "sem.h"
int main(int argc, const char *argv[])
{
//a. 创建信号灯集
int semid = create_sem(2);
if(semid == -1){
perror("create_sem error");
return -1;
}
printf("semsnd semid %d\n",semid);
//1.创建key
key_t key = ftok("/",'k');
if(key == -1){
perror("ftok error");
return -1;
}
printf("semsnd key %#x\n",key);
//2.通过key 创建共享内存段
int ipc = shmget(key,PAGE_SIZE,IPC_CREAT|0664);
if(ipc == -1){
perror("shmget error");
return -1;
}
printf("semsnd ipc %d\n",ipc);
//3. 将共享内存映射到用户空间
char *addr = (char *)shmat(ipc,NULL,0);
if(addr == (void*)-1){
perror("shmat error");
return -1;
}
printf("semsnd ------------------------\n");
//4. 使用共享内存
while(1){
//循环往共享内存写入数据
//b. P操作,等待 1号灯
p_handle(semid,1);
printf("请输入>>>");
fgets(addr,PAGE_SIZE,stdin);
addr[strlen(addr)-1] = 0;
//c. V操作 释放 0 号灯
v_handle(semid,0);
if(strcmp(addr,"tuichu") == 0){
break;
}
}
//5. 取消映射
if(shmdt(addr) == -1){
perror("semsnd shmdt error");
return -1;
}
return 0;
}
#include "sem.h"
int main(int argc, const char *argv[])
{
int semid = create_sem(2);
if(semid == -1){
perror("semaccept semid error");
return -1;
}
printf("semaccept semid %d\n",semid);
//接收内存消息
key_t key = ftok("/",'k');
if(key == -1){
perror("accept ftok error");
}
printf("semaccept key %#x\n",key);
//2.通过key 创建共享内存段
int ipc = shmget(key,PAGE_SIZE,IPC_CREAT|0664);
if(ipc == -1){
perror("shmget error");
return -1;
}
printf("semaccept ipc %d\n",ipc);
//3. 将共享内存映射到用户空间
char *addr = (char *)shmat(ipc,NULL,0);
if(addr == (void*)-1){
perror("shmat error");
return -1;
}
printf("semaccept +++++++++++++++++++++++++ \n");
//4.循环消费
while(1){
//b.P操作 0 号灯
p_handle(semid,0);
printf("消费到的消息%s\n",addr);
//C. V操作 1 号灯
v_handle(semid,1);
if(strcmp(addr,"tuichu") == 0){
break;
}
}
//5.取消映射
if(shmdt(addr) == -1){
perror("accept shmdt error");
return -1;
}
//6.删除共享内存
if(shmctl(ipc,IPC_RMID,NULL) == -1){
perror("shmctl error");
return -1;
}
//7.删除信号灯
del_sem(semid);
return 0;
}
3. 思维导图