Linux下使用信号量实现PV操作

 一.信号量与PV操作概述

在多道程序系统中,由于资源共享与进程合作,使各进程之间可能产生两种形式的制约关系,一种是间接相互制约,例如,在仅有一台打印机的系统,同一时刻只能有一个进程分配到到打印机,其他进程必须阻塞;另一种是直接相互制约,例如进程A通过单缓冲去向进程B提供数据,当改缓冲区为空时,进程B不能获取所需的数据而阻塞,一旦进程A将数据送入缓冲区,进程B就被唤醒,反之,当缓冲区满时,进程A被阻塞,仅当进程B取走缓冲区的数据时,才唤醒进程A。

进程同步主要源于进程合作,是进程之间共同完成一项任务时直接发生相互作用的关系,为进程之间的直接制约关系。

进程互斥主要源于资源共享是进程之间的间接制约关系。在多道程序系统中,每次只允许一个进程访问的资源称为临界资源,进程互斥要求保证每次只有一个进程使用临界资源。在每个进程中访问临界资源的程序段称为临界区,进程进入临界区要满足一定的条件,以保证临界资源的安全使用和系统的正常运行。

PV操作是对信号量进行处理的操作过程,而且信号量只能由PV操作来改变。P操作是对信号量减去1,意味着请求系统分配一个单位资源,若系统无可用资源,则进程变为阻塞状态;V操作是对信号量加1,意味着释放一个资源,加1后若信号量小于等于0,则从就绪队列中唤醒一个进程,执行V操作的进程继续执行。

二.Linux系统下程序示例

 在Linux系统中,通常调用semget,semctl,semop这些API来实现。

首先,需要调用 semget函数创建信号量或获得在系统中已存在的信号量。不同进程通过使用同一个信号量键值来获得同一个信号量。其次,使用 semctl函数的SETVAL操作来初始化信号量,此时。当使用二维信号量时,通常将信号量初始化为1。接下来就是调用 semop函数进行信号量的PV操作。最后如果不需要信号量,则使用semctl函数的 IPC_RMID操作从系统中删除它。

在这里以Linux下的C程序与例子,简单验证下使用信号量实现PV操作的原理。

1.在Linux下创建一个名为pv_test的工程目录。

2.创建一个sem_pv.c的文件,写入以下代码。

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdarg.h>
#include <time.h>#define SEM_P -1
#define SEM_V 1#if !(defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED))
//如果系统中没有定义这个联合体,则需要额外定义一下
union semun {int val;                             struct semid_ds *buf;    unsigned short int *array; struct seminfo *__buf;  
};
#endif//获取时间戳
int get_timestamp(char *timestamp)
{time_t timep;struct tm *p, pp;time(&timep);localtime_r(&timep, &pp);p = &pp;return sprintf(timestamp, "%04d-%02d-%02d %02d:%02d:%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);}/*
日志打印
*/
void LOG(const char *format,...)
{va_list argptr;char buffer[2048];va_start(argptr,format);vsprintf(buffer,format,argptr);va_end(argptr);char timestamp[64]="";get_timestamp(timestamp);printf("[%s][%d]%s", timestamp, getpid(), buffer);
}int sem_init(int semid) 
{int ret;union semun semun;semun.val = 0;ret = semctl(semid, 0, SETVAL, semun);if (ret == -1) {LOG("semctl failed!\n");}return ret;
}int semop_pv(int semid, int opt)
{int ret;struct sembuf sembuf;sembuf.sem_op = opt;sembuf.sem_num = 0;//初始化为0,表示暂时没资源sembuf.sem_flg = SEM_UNDO;ret = semop(semid, &sembuf, 1);	if (ret == -1) {LOG("sem_p failed!\n");}return ret;
}/*
模拟P操作
*/int  semop_p(int semid)
{//p操作 对信号量进行减1LOG("semctl P\n");return semop_pv(semid, SEM_P);
}/*
模拟V操作
*/int  semop_v(int semid)
{//v操作 对信号量进行加1LOG("semctl V\n");return semop_pv(semid, SEM_V);
}/*
删除信号量
*/
void sem_del(int semid)
{union semun sem_un;if(semctl(semid, 0, IPC_RMID, sem_un)<0) {LOG("sem_del fail\n");}
}

 3.创建一个名为“main.c”的文件,写入以下代码:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <time.h>#define TEST_FILE "./test"int file_write()
{char timestamp[64]="";FILE *fp = fopen(TEST_FILE, "ab+");if(!fp) {LOG("[%s](%d)open %s failed!\n", __func__, __LINE__, TEST_FILE);return -1;}get_timestamp(timestamp);
//将进程号写入文件fprintf(fp, "[%s]Process (%d)write!!!\n", timestamp, getpid());fclose(fp);return 0;
}int main(int argc, char* argv[]) 
{int i;int ret;int semid;int timeout = 5;//测试写文件操作5次int sleep_second = 1;/* 获取信号量  键值设置为6666, 1表示信号量的数量, 后面表示如果没有这个信号量就创建而且设置为都可以访问的权限*/semid = semget((key_t)6666, 1, 0666 | IPC_CREAT);/*如果没有创建成功就会返回-1 然后打印失败的信息*/LOG("semid=%d\n", semid);if (semid == -1) {LOG("semget failed!\n");exit(1);}/* 初始化信号量 */ret = sem_init(semid);if (ret == -1) {exit(1);}if(argc<2) {LOG("Input error!!!\n");exit(0);}int param = atoi(argv[1]);if(param==1) {
//参数为1的进程进行V操作if (semop_v(semid) == -1) {exit(1);}sleep(1);}else {unlink(TEST_FILE);}while(timeout--) {
//刚开始if (semop_p(semid) == -1) {exit(1);}/* 临界区操作*/LOG("begin write\n");file_write();sleep(sleep_second);LOG("write done!\n");if (semop_v(semid) == -1) {exit(1);}}/* 删除信号量 */if(param==1) {sem_del(semid);}return 0;
}

 4.创建一个Makefile文件,写入以下内容:

CPROG	= pv_test
BIN     = $(CPROG) 
CC= gcc
OBJS=main.o sem_pv.oall: $(BIN) 
clean:rm -f $(OBJS) $(BIN)
$(BIN): $(OBJS)$(CC)  -o $(BIN) $(OBJS)   $(CFLAGS) $(LDFLAGS) $(CFLAGS_EXTRA) 

5.在当前目录下执行make clean;make编译生成一个pv_test可执行文件

6.测试。运行时,使用参数0和1来区分不同的进程。

 

查看写入的文件,可以看到两个进程交替写文件,如下所示:

总结:

信号量不仅是一种进程之间的通信机制,与此同时,信号量的使用,可以有效的解决进程间的同步与互斥问题。信号量的PV操作是实现进程间的同步和互斥的核心工作部分。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ONLYOFFICE | 免费开源办公神器新选择

目录 前言&#xff1a; 1、什么是ONLYOFFICE&#xff1f; 2、ONLYOFFICE下载使用 3、ONLYOFFICE团队协作云办公功能 4、ONLYOFFICE 8.0新版本的亮点功能 4.1、显示协作者头像 4.2、插件 UI 界面更新 4.3、可填写的 PDF 表单 5、最后 前言&#xff1a; 一个好的开发工具…

(五)MySQL的备份及恢复

1、MySQL日志管理 在数据库保存数据时&#xff0c;有时候不可避免会出现数据丢失或者被破坏&#xff0c;这样情况下&#xff0c;我们必须保证数据的安全性和完整性&#xff0c;就需要使用日志来查看或者恢复数据了 数据库中数据丢失或被破坏可能原因&#xff1a; 误删除数据…

PyTorch深度学习实战(34)——Pix2Pix详解与实现

PyTorch深度学习实战&#xff08;34&#xff09;——Pix2Pix详解与实现 0. 前言1. 模型与数据集1.1 Pix2Pix 基本原理1.2 数据集分析1.3 模型构建策略 2. 实现 Pix2Pix 生成图像小结系列链接 0. 前言 Pix2Pix 是基于生成对抗网络 (Convolutional Generative Adversarial Netwo…

[数据结构]-哈希

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标&…

Golang 流媒体服务器lalserver使用指南

目录 安装 使用 1.推流 2.播放 官方地址 安装 1.下载源码 wget https://github.com/q191201771/lal/releases/download/v0.36.7/lal_v0.36.7_linux.zipunzip lal_v0.36.7_linux.zip cd lal_v0.36.7_linux 2.启动 ./bin/lalserver -c ./conf/lalserver.conf.json 使用 …

蓝桥杯---牌型种数

小明被劫持到X赌城&#xff0c;被迫与其他3人玩牌。一副扑克牌(去掉大小王牌,共52张)&#xff0c;均匀发给4个人&#xff0c;每个人13张。这时&#xff0c;小明脑子里突然冒出一个问题&#xff1a;如果不考虑花色&#xff0c;只考虑点数&#xff0c;也不考虑自己得到的牌的先后…

WSL2+ubuntu 18+VsCode 配置C/C++开发环境 踩坑

1. 管理员模式打开cmd&#xff0c;或PowerShell &#xff0c;输入 wsl --install 可能出现的错误&#xff1a;无法解析服务器名称或地址 解决方式&#xff1a;科学上网 安装WSL时遇到“无法解析服务器名称或地址”的错误及解决方法 - 知乎 错误2&#xff1a;Error 0x8037…

黑马程序员前端web入门:新浪新闻

黑马程序员前端web入门&#xff1a;新浪新闻 几点学习到的&#xff1a; 设置li无圆点: list-style: none;设置a无下划线&#xff1a;text-decoration: none;a属于行内元素&#xff0c;高度hegiht不起作用&#xff0c;可以设置 display: block; 把它变成块元素。此时&#xff0c…

vue3-hand-mobile

当我写完手势移动事件后&#xff0c;我又通过svg的方法添加了一段文字和polygon。当我在这个蓝色的polygon上滑动手势的时候&#xff0c;会报错。 可能这个bug只是我个人的代码导致的。但是我觉得vue3-hand-mobile插件的这一段代码写的有问题。 我通过circular-json库修复了这…

OpenGL ES 渲染 NV21、NV12 格式图像有哪些“姿势”?

使用2个纹理实现 NV21 格式图像渲染 前文提到渲染 NV21 格式图像需要使用 2 个纹理,分别用于保存 Y plane 和 UV plane 的数据,然后在片段着色器中分别对 2 个纹理进行采样,转换成 RGB 数据。 OpenGLES 渲染 NV21或 NV12 格式图像需要用到 GL_LUMINANCE 和 GL_LUMINANCE_A…

cocos creator 调用预设体Prefab中的方法(调用另一个节点的方法)

调用预设体中的方法 通过cc.instantiate(this.star)创建这个预设体实例这个star预设体中添加了一个脚本组件star.ts 获取到这个脚本组件star.getComponent(‘star’).test()&#xff0c;并调用其中的test()方法同理可以用该方式像另一个节点中传值 //星星预设体property(cc.Pr…

idea中yml文件没有提示解决办法

两步解决yml文件不显示提示&#xff0c;yaml文件显示提示问题 1、在插件中心&#xff0c;先下载下图两个插件 2、在Editor》File Types新增文件类型&#xff0c;文件名匹配规则需要将yaml和yml的都加上&#xff0c;加好之后&#xff0c;重启idea&#xff0c;即刻生效。

java基础(面试用)

一、基本语法 1. 注释有哪几种形式&#xff1f; //单行注释&#xff1a;通常用于解释方法内某单行代码的作用。 //int i 0;//多行注释&#xff1a;通常用于解释一段代码的作用。 //int i 0; //int i 0;//文档注释&#xff1a;通常用于生成 Java 开发文档。 /* *int i 0; …

【LeetCode: 25. K 个一组翻转链表 + 链表 + 递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

解读——SuperMap iClient3D for Cesium使用柱体截面绘制河流

原文参考 SuperMap iClient3D for Cesium绘制河流&#xff08;二&#xff09;_cesium polylinevolume 管道流向添加-CSDN博客 river viewer.entities.add({name : river,polylineVolume : {positions: new Cesium.Cartesian3.fromDegreesArrayHeights(positions), //节点坐…

《Lua程序设计》-- 学习9

迭代器和泛型for 迭代器和闭包 迭代器&#xff08;iterator&#xff09;是一种可以让我们遍历一个集合中所有元素的代码结构。在Lua语言中&#xff0c;通常使用函数表示迭代器&#xff1a;每一次调用函数时&#xff0c;函数会返回集合中的“下一个”元素。 一个闭包就是一个…

C/C++ - 类的封装特性

目录 类的封装 语法格式 声明定义 分文件 访问权限 类作用域 对象模型 构造函数 默认构造函数 带参构造函数 拷贝构造函数 构造函数重载 委托构造函数 初始数据列表 构造默认参数 构造函数删除 析构函数 析构函数概念 析构函数特性 析构函数示例 析构调用…

AIGC项目——Meta:根据对话音频生成带动作和手势的3d逼真数字人

From Audio to Photoreal Embodiment: Synthesizing Humans in Conversations From Audio to Photoreal Embodiment:Synthesizing Humans in Conversations 从二元对话的音频中&#xff0c;我们生成相应的逼真的面部、身体和手势。 概括性:角色是由作者的声音驱动的(而不是模…

【解决视网膜长尾数据】实例级类平衡、层次预训练、混合知识蒸馏

解决视网膜长尾数据&#xff1a;实例级类平衡、层次预训练、混合知识蒸馏 问题&#xff1a;视网膜疾病分类&#xff0c;解法&#xff1a;深度学习模型问题&#xff1a;数据复杂性处理&#xff0c;解法&#xff1a;多任务框架&#xff08;同时处理多种疾病&#xff09;和少量样本…

TSINGSEE青犀视频智慧电梯管理平台,执行精准管理、提升乘梯安全

一、方案背景 随着城市化进程的不断加快&#xff0c;我国已经成为全球最大的电梯生产和消费市场&#xff0c;电梯也成为人们日常生活中不可或缺的一部分。随着电梯数量的激增&#xff0c;电梯老龄化&#xff0c;维保数据不透明&#xff0c;物业管理成本高&#xff0c;政府监管…