当前位置: 首页 > article >正文

Linux 基本语句_14_信号灯实验

原理:

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程序

效果:

在这里插入图片描述


http://www.kler.cn/news/155976.html

相关文章:

  • Hdoop学习笔记(HDP)-Part.06 安装OracleJDK
  • 【Java基础系列】BigDecimal入门
  • GB/T 37380-2019抗污易洁涂膜玻璃检测
  • Paxos 算法
  • 算法通关村第十六关-白银挑战滑动窗口经典题目
  • 第十七章 其他-rpc、rabbitmq(如何对消息做持久化、如何控制消息被消费的顺序)、celery(应用场景、运行机制、如何实现定时任务)
  • postgres在docker中使用
  • LeetCode刷题---反转链表
  • SCAU:链表创建与插入结点(填空)
  • word表格图片批处理参考程序
  • Linux-usb触摸板去除鼠标箭头
  • Ubuntu20.24 安装ecCodes,包括 tar.gz 和 python(笔记)
  • [网络安全]dos命令
  • Sakila数据库和World数据库
  • Vue+ElementUI+C#前后端分离:监控长耗时任务的实践
  • [足式机器人]Part4 南科大高等机器人控制课 Ch00 课程简介
  • C语言,求取数组的序亏:已知一个整数数组,求出个数组中每个元素在整个 数组的排序。
  • 鸿蒙(HarmonyOS)应用开发——构建页面(题目答案)
  • 93. 复原 IP 地址
  • 华为手环配置技巧
  • Java 中 IO 流分为几种?
  • 【算法思考记录】力扣1423. 可获得的最大点数[Python3, 滑动窗口]
  • golang 实现单向链表(lru)、双向链表、双向循环链表
  • Error:cannot launch node of type [map_server/map_server]
  • A++ 敏捷开发-1 如何改善
  • 常微分方程组的数值解法(C++)
  • WPS开发文档
  • Android:BackStackRecord
  • KALI LINUX安全审核
  • 实时设计#N3期训练营DONE,ComfyUI中文社区@上海