【Linux系统编程】08:信号量

news2025/7/16 3:12:12

信号量


OVERVIEW

  • 信号量
        • 1.mmap内存映射
        • 2.semget信号量获取
        • 3.semctl信号量控制
        • 4.semop信号量操作
        • 5.使用案例

在这里插入图片描述

1.mmap内存映射

mmap映射的是磁盘中的文件,而共享内存是将内存映射到用户的进程空间中

原型:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

  • addr:映射的地址空间(如果为空则内核将会自动选择映射的位置)
  • length:映射的长度
  • prot:对映射内容的保护方式
  • flag:标记位
  • fd:文件描述符
  • offset:偏移量
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/**
 * 打开一个文件 将文件映射到进程的地址空间中
 * 然后通过设定一些偏移量 来拿到文件的一些内容
*/
#define handle_error(msg) \
	do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char *argv[]) {
	struct stat sb;
	off_t offset, pa_offset;
	size_t length;
	//1.命令解析
	if (argc < 3 || argc > 4) {
		fprintf(stderr, "%s file offset [length]\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	//2.打开文件
	int fd = open(argv[1], O_RDONLY);
	if (fd == -1) handle_error("open");
	//3.确定偏移量及其错误处理
	if (fstat(fd, &sb) == -1) handle_error("fstat");//获取文件长度
	offset = atoi(argv[2]);
	pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);//做页对齐的机制 _SC_PAGE_SIZE页面的大小
	//偏移量大于最大文件长度
	if (offset >= sb.st_size) {
		fprintf(stderr, "offset is past end of file\n");
		exit(EXIT_FAILURE);
	}
	//偏移量+length大于最大文件长度
	if (argc == 4) {
		length = atoi(argv[3]);
		if (offset + length > sb.st_size) length = sb.st_size - offset;
	} else {
		length = sb.st_size - offset;
	}
	//4.调用mmap进行内存映射
	char *addr = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_PRIVATE, fd, pa_offset);
	if (addr == MAP_FAILED) handle_error("mmap");
	//5.对需要输出的字符进行打印
	ssize_t s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
	if (s != length) {
		if (s == -1) handle_error("write");
		fprintf(stderr, "partial write");
		exit(EXIT_FAILURE);
	}
	//6.解开映射关系
	munmap(addr, length + offset - pa_offset);
	close(fd);
	exit(EXIT_SUCCESS);
}

2.semget信号量获取

在这里插入图片描述

3.semctl信号量控制

在这里插入图片描述

4.semop信号量操作

在这里插入图片描述

5.使用案例

  1. 创建一个信号量,初始化设置其val为2(每次只有2个进程能够拿到资源)
  2. 对临界资源进行PV操作
  3. 模拟多个非亲缘关系的进程,对该临界资源访问时的情况
  4. 当每个进程访问该临界资源时输出自己是第几次访问即可
#include "head.h"

#define handle_error(msg) \
	do { perror(msg); exit(EXIT_FAILURE); } while (0)

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) */
};

//1.创建信号量
int create_sem(const char pathname[], int proj_id, int nsmes) {
	key_t key = ftok(pathname, proj_id);
	int sem_id;
	if ((sem_id = semget(key, nsmes, IPC_CREAT | 0600)) < 0) return -1;//获取信号量集合的识别号
	return sem_id;
}

//2.初始化信号量
int init_sem(int sem_id, int sem_num, int val) {
	union semun arg;
	arg.val = val;//可选操作
	return semctl(sem_id, sem_num, SETVAL, arg);//操作设置为SETVAL
}

//3.定义PV操作
//struct sembuf, containing the following members:
// unsigned short sem_num;  //semaphore number
// short          sem_op;   //semaphore operation
// short          sem_flg;  //operation flags

int P(int sem_id, int sem_num) {//用于判定PV操作是否成功
	struct sembuf sembuff;
	sembuff.sem_num = sem_num;//要操作的是第几个信号量
	sembuff.sem_op = -1;//P操作为-1
	sembuff.sem_flg = SEM_UNDO;//SEM_UNDO当进程结束时 该操作也会自动的将资源释放
	if (semop(sem_id, &sembuff, 1) < 0) return -1;//调用semop进行P-1操作
	return 0;
}

int V(int sem_id, int sem_num) {//用于判定PV操作是否成功
	struct sembuf sembuff;
	sembuff.sem_num = sem_num;//要操作的是第几个信号量
	sembuff.sem_op = 1;//P操作为-1
	sembuff.sem_flg = SEM_UNDO;
	if (semop(sem_id, &sembuff, 1) < 0) return -1;//调用semop进行V+1操作
	return 0;
}

int main(int argc, char* argv[]) {
	//1.创建一个信号量 只有首个进程进行信号量初始化操作
	int sem_id;
	if ((sem_id = create_sem("1.sem.c", 123, 1)) < 0) handle_error("create_sem");
	if (argc > 1) {//并不是所有的进程都在需要进行初始化操作
		if ((init_sem(sem_id, 0, 2) < 0)) handle_error("init_sem");//val设置为2 每次有2个进程能够拿到资源
	}
	
	//2.pv操作 让多个非亲缘关系的进程拿到资源
	int times;
	while (1) {
		if (P(sem_id, 0) < 0) handle_error("P");
		sleep(3);
		times++;
		if (V(sem_id, 0) < 0) handle_error("V");
		//3.输出我时第几次拿到资源
		printf("this is %dth time i got the resource!\n", times);
	}
	return 0;
}

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/404915.html

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

相关文章

DHCP中继配置

1. 实验目的 熟悉DHCP中继的应用场景掌握DHCP中继的配置方法2. 实验拓扑 DHCP中继配置实验拓扑如图15-10所示: 图15-10:DHCP中继配置 3. 实验步骤 IP地址的配置AR1的配置 <Huawei>system-view

VCO pulling

这次调试项目 目前复现的问题 2.4g干扰到5g 问题就是2.4g 5g 同时发包&#xff0c;5g evm直接从37-38变成33-34 于是我对vco-pulling做了一个小结 VCO pulling是指当一个外部信号对振荡器的频率产生影响时&#xff0c;振荡器的频率将被拉动或偏移。这种现象通常会在无线电通…

SpringBoot嵌入式Servlet容器 相关学习笔记

大家都知道SrpingBoot是内嵌Servlet容器的&#xff0c;并且默认是Tomcat&#xff0c;本文主要讲一下其中原理。   首先&#xff0c;SpringBoot是支持其它容器的&#xff0c;除了Tomcat外&#xff0c;还有Undertow&#xff0c;Netty以及Jetty。并且这些容器经过封装&#xff0c…

KAT: A Knowledge Augmented Transformer for Vision-and-Language

Paper name KAT: A Knowledge Augmented Transformer for Vision-and-Language Paper Reading Note URL: https://arxiv.org/pdf/2112.08614.pdf TL;DR 2022 NAACL 论文&#xff0c;提出了 Knowledge AugmentedTransformer (KAT)&#xff0c;提出了一种同时利用显式和隐式…

记录第一次安装部署datadonphon遇到的坑和解决办法

故事开始之前&#xff0c;我在3台服务器里新建了一个abin用户&#xff0c;3台服务器都用abin和root账号做了免密登录。故事开始了......按照官网文档一顿操作猛如虎到了配置集群了。那就配置呗&#xff0c;点它。仔细阅读了提示&#xff0c;嗯&#xff0c;明白它的意思了。来吧…

Python进阶-----高阶函数->filter() 函数

目录 前言&#xff1a; filter() 函数介绍 filter() 函数使用示例 1.与循环对比 2.与lambda函数综合使用 3.使用None过滤False 4.过滤字典相关数据 前言&#xff1a; 家人们&#xff0c;当你们获取了一个序列的时候&#xff0c;想要把一些内容去掉&#xff0c;保留一部分…

《JavaEE》进程和线程的区别和联系

&#x1f451;作者主页&#xff1a;Java冰激凌 &#x1f4d6;专栏链接&#xff1a;JavaEE 目录 进程是什么&#xff1f; 线程是什么&#xff1f; 进程和线程之间的联系~ ps1&#xff1a;假设我们当前的大兴国际机场有一条登机口可以登入飞机 ps2&#xff1a;我们为…

运动员最佳匹配问题(详解)

一、问题描述 羽毛球队有男女运动员各n人。给定2个nn矩阵P和Q。 P[i][j]是男运动员i的女运动员j配对组成混合双打的男运动员竞赛优势&#xff1b;Q[i][j]是女运动员i和男运动员j配对的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响&#xff0c;P[i][j]不一定等于Q[…

LearnOpenGL-光照-6.多光源

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject 文章目录前言例子代码没有聚光灯效果有聚光灯效果前言 此节目的 综合2.5投光物&#xff0c;在此节实现一个场…

超越语言界限,ChatGPT进化之路——Visual ChatGPT

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

操作系统复习

熟练掌握操作系统的定义&#xff0c;操作系统的特征&#xff0c;操作系统的功能熟练掌握多道程序设计的概念&#xff0c;单道程序设计和多道程序设计的区别&#xff0c;多道程序设计的优点熟悉操作系统接口的主要功能&#xff0c;系统调用的基本概念、类型、实现。操作系统接口…

【Mysql】库的操作

一、sql分类 1.DDL&#xff08;Data Defination Language&#xff09;数据定义语言 定义数据时候使用的sql语言 creat:建表、drop:删表、alter:改变 2.DML&#xff08;Data Manipulation Language&#xff09;数据操纵语言 对数据进行操作的sql语言 insert:插入、delet…

【打造家庭服务器系列03】Frp 实现内网穿透

一、概述 为什么要搞frp&#xff0c;因为我们的服务器处于家里面的网络&#xff0c;是没有公网IP的&#xff0c;所以直接通过ssh连接服务器&#xff0c;此时就需要一个中转来实现转发。 二、服务端配置 - Frp Server 以腾讯云为例&#xff0c;阿里云也一样。Frp 官方文档 -…

chatPDF | 别再自己读文献了!让chatGPT来帮你读吧!~

1写在前面 自从chatGPT开放API以后&#xff0c;相关基于此的app也是层出不穷。&#x1f92a; ChatGPT API是基于OpenAI的自然语言处理模型的API。&#x1f9d0; 基于这个API&#xff0c;开发人员可以通过程序调用和使用ChatGPT模型来解决各种文本相关的任务。&#x1f609; 其实…

Ubuntu软件包管理之apt与apt-get的区别

目录apt和apt-get发展史apt和apt-get命令对比常用命令举例更新存储库索引升级已安装的包列出所有可用安装包关键字搜索安装包安装软件卸载软件查看安装包信息清理没用的依赖包清理下载的缓存包清理残余的配置文件查看安装包的依赖参考apt和apt-get发展史 Debian 使用一套名为 …

STM32—LCD1602

LCD1602&#xff08;Liquid Crystal Display&#xff09;是一种工业字符型液晶&#xff0c;能够同时显示 1602 即 32 字符(16列两行) 第 1 脚: VSS 为电源地 第 2 脚: VDD 接 5V 正电源 第 3 脚: VL 为液晶显示器对比度调整端,接正电源时对比度最弱&#xff0c;接地时对比度最…

C语言实现快速排序(hoare法、挖坑法、前后指针法与非递归实现)——不看后悔系列

目录 1. hoare法 方法与步骤 代码实现 2. 挖坑法 方法与步骤 代码实现 3. 前后指针法 方法与步骤 代码实现 4. 快速排序的缺点与优化 1.快速排序的缺点 2.快速排序的优化 ① 三数取中法选 key 代码实现 ② 小区间优化 代码实现 5. 快速排序的非递归实现 附录…

数据结构与算法基础(王卓)(16):KMP算法详解(代码实现)

实现代码的过程中 具体细节、问题&#xff1a; &#xff08;1&#xff09;&#xff1a;关于写Get_next函数的标题&#xff1a; 现象&#xff1a; PPT上写的是&#xff1a; void get_next(SString T, int &next[]) 然而并不能运行&#xff0c;而当我们去掉了引用符号&…

记录踩过的坑-Git

Git命令克隆很慢原命令&#xff1a;git clone -b r1.13.0 https://github.com/tensorflow/models.git现在替换为&#xff1a;git clone -b r1.13.0 https://github.com.cnpmjs.org/tensorflow/models.git也就是把原 URL 中的 github.com 替换为 github.com.cnpmjs.org&#xff…

设计模式第9式:迭代器模式

前言 我们有很多种方法可以把对象集中到一个集合中&#xff0c;比如列表、堆栈、散列表中。每种集合都有自己的特点和使用时机&#xff0c;但都有一个共同的需求&#xff1a;用户想要遍历这些对象。同时我们并不想用户看到集合的实现&#xff0c;本文将讲解如何让用户遍历对象…