Linux 基本语句_14_信号灯实验

news2025/1/15 7:47:29

原理:

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.coloradmin.cn/o/1281402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Node.js】Node.js环境下载与安装教程(Windows系统)

前言 Node.js是一个基于Chrome V8引擎的JavaScript运行时环境&#xff0c;可以让你使用JavaScript进行服务器端编程。本教程将向你展示如何在Windows系统上下载和安装Node.js环境。 下载 首先&#xff0c;你需要下载Node.js环境。 打开Node.js官方网站&#xff1a;https://no…

Leetcode2661. 找出叠涂元素

Every day a Leetcode 题目来源&#xff1a;2661. 找出叠涂元素 解法1&#xff1a;哈希 题目很绕&#xff0c;理解题意后就很简单。 由于矩阵 mat 中每一个元素都不同&#xff0c;并且都在数组 arr 中&#xff0c;所以首先我们用一个哈希表 hash 来存储 mat 中每一个元素的…

C语言中的动态内存管理

在C语言中&#xff0c;动态内存管理是通过一系列的标准库函数来实现的&#xff0c;这些函数包括malloc, free, calloc 和 realloc。它们允许程序在运行时动态地分配和释放内存&#xff0c;这是管理复杂数据结构&#xff08;如链表、树等&#xff09;时非常有用的功能。 为什么…

为何要3次握手?TCP协议的稳定性保障机制

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

MYSQL练题笔记-聚合函数-每月交易

一、题目相关内容 1&#xff09;相关的表和题目 2&#xff09;帮助理解题目的示例&#xff0c;提供返回结果的格式 二、初步的理解 是需要知道每个月和每个国家/地区的事务数及其总金额&#xff0c;每个月和每个国家/地区已批准的事务数及其总金额&#xff1b;以上的理解还是…

RPC和REST对比

RPC和REST对比 参考学习 RPC 和 REST 之间有什么区别&#xff1f; 当我们对比RPC和REST时&#xff0c;其实是在对比RPC风格的API和REST风格的API&#xff0c;后者通常成为RESTful API。 远程过程调用&#xff08;RPC&#xff09;和 REST 是 API 设计中的两种架构风格。API …

【计算机组成原理】存储器知识

目录 1、存储器分类 1.1、按存储介质分类 1.2、按存取方式分类 1.3、按信息的可改写性分类 1.4、按信息的可保存性分类 1.5、按功能和存取速度分类 2、存储器技术指标 2.1、存储容量 2.2、存取速度 3、存储系统层次结构 4、主存的基本结构 5、主存中数据的存放 5.…

分类预测 | Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量输入数据分类预测

分类预测 | Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量输入数据分类预测 目录 分类预测 | Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量输入数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现FA-SVM萤火虫算法优化支持向量机的多变量…

网络安全现状

威胁不断演变&#xff1a; 攻击者不断变化和改进攻击方法&#xff0c;采用更复杂、更隐秘的技术&#xff0c;以逃避检测和追踪。这包括新型的勒索软件、零日漏洞利用和社交工程攻击等。 供应链攻击&#xff1a; 攻击者越来越关注供应链的弱点&#xff0c;通过在供应链中植入恶…

Gitee拉取代码报错You hasn‘t joined this enterprise! fatal unable to access

文章目录 一、问题二、解决2.1、进入**控制面板**2.2、进入**用户账户**2.3、进入**管理Windows凭据**2.4、**普通凭据**2.4.1、添加2.4.2、编辑 2.5、重新拉取|推送代码 三、最后 一、问题 Gitee拉取仓库代码的时候报错You hasnt joined this enterprise! fatal unable to ac…

小米秒享3--非小米电脑

小米妙享中心是小米最新推出的一款功能&#xff0c;能够为用户们提供更加舒适便利的操作体验。简单的说可以让你的笔记本和你的小米手机联动&#xff0c;比如你在手机的文档&#xff0c;连接小米共享后&#xff0c;可以通过电脑进行操作。 对于非小米电脑想要体验终版秒享AIOT…

Spring Task 定时任务框架

Spring Task Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 定位&#xff1a;定时任务框架 作用&#xff1a;定时自动执行某段Java代码 Spring Task使用步骤 1). 导入maven坐标 spring-context&#xff08;已存在&#xff…

如何在忘记密码的情况下恢复解锁 iPhone

您忘记了 iPhone 密码吗&#xff1f;Apple 官方通常建议将 iPhone 恢复至出厂设置以将其删除。这种修复很不方便&#xff0c;甚至可能比问题本身更麻烦。 如果您也经历过同样的情况&#xff0c;并且想知道忘记了 iPhone 密码并且不想恢复它该怎么办&#xff0c;我们的终极指南…

本项目基于Spring boot的AMQP模块,整合流行的开源消息队列中间件rabbitMQ,实现一个向rabbitMQ

在业务逻辑的异步处理&#xff0c;系统解耦&#xff0c;分布式通信以及控制高并发的场景下&#xff0c;消息队列有着广泛的应用。本项目基于Spring的AMQP模块&#xff0c;整合流行的开源消息队列中间件rabbitMQ,实现一个向rabbitMQ添加和读取消息的功能。并比较了两种模式&…

Flutter PK jetpack compose区别和选择

Flutter诞生于Chrome团队&#xff0c;是一帮做Web的开发做的跨平台框架&#xff0c;从最开始的设计初衷&#xff0c;就是指向了跨平台这条路&#xff0c;而Compose&#xff0c;则是诞生于Android团队&#xff0c;是为了解决当前View的架构体系不能再继续适应申明式编程的范式而…

Nginx的反向代理与负载均衡

概念介绍 1). 正向代理 正向代理服务器是一个位于客户端和原始服务器(origin server)之间的服务器&#xff0c;为了从原始服务器取得内容&#xff0c;客户端向代理发送一个请求并指定目标(原始服务器)&#xff0c;然后代理向原始服务器转交请求并将获得的内容返回给客户端。 …

如何购买阿里云服务器

作为一家全球领先的云计算服务提供商&#xff0c;阿里云提供了多种云产品和解决方案&#xff0c;包括云服务器、对象服务OSS、数据库、存储、SSL、域名和CDN等。阿里云服务器是一种灵活可扩展的云计算服务&#xff0c;适用于各种规模和类型的企业和个人用户。阿里云以其出色的性…

专业课:递归非递归中序遍历

非递归中序遍历二叉树通常使用栈来辅助实现。 树结构&#xff1a; struct TreeNode {int data;TreeNode* left;TreeNode* right; };递归 void inorderTraversal(TreeNode *root){if(root ! nullptr){//中序遍历 “左孩子--根节点--右孩子”inOrder(root->lchild);printf(…

「Swift」类淘宝商品瀑布流展示

前言&#xff1a;需要做一个类似于淘宝商品页面的瀑布流展示 结构分析&#xff1a; ps&#xff1a;图片来源 思路分析&#xff1a; 该瀑布流主要还是基于UICollectionView进行展示&#xff0c;只是在cell展示的UICollectionViewFlowLayout需要进行相应调整和自定义&#xff…

[ 云计算 | AWS 实践 ] 使用 Java 检查指定的密钥是否存在于给定的 Amazon S3 存储桶中

本文收录于【#云计算入门与实践 - AWS】专栏中&#xff0c;收录 AWS 入门与实践相关博文。 本文同步于个人公众号&#xff1a;【云计算洞察】 更多关于云计算技术内容敬请关注&#xff1a;CSDN【#云计算入门与实践 - AWS】专栏。 本系列已更新博文&#xff1a; [ 云计算 | …