day16 信号灯

news2024/9/29 21:24:47

信号灯概念和有名信号灯

目录

信号灯概念和有名信号灯

有名信号灯

无名信号灯

信号灯P操作

信号灯V操作

system V信号灯的


 

信号灯/信号量(semaphore)

信号量代表某一类资源,其值表示系统中该资源的数量;

信号量是一个受保护的变量,只能通过三种操作来访问

初始化、P操作(申请资源)、V操作(释放资源)(P消费者、V生产者)

概念:

是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的PV操作概念:

生产者和消费者场景
P(S) 含义如下:
     if  (信号量的值大于0) {  
 申请资源的任务继续运行;
           信号量的值减一;
} else {   
申请资源的任务阻塞;
} 
V(S) 含义如下:
     信号量的值加一;
     if (有任务在等待资源) {   
唤醒等待的任务,让其继续运行 
}

三种信号灯:

Posix  有名信号灯;

Posix  无名信号灯;

System V 信号灯;

Posix 有名信号灯和无名信号灯使用:

有名信号灯

有名信号灯打开:

sem_t *sem_open(const char *name, int oflag);
sem_t*sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

参数:

name:name是给信号灯起的名字;

oflag:打开方式,常用O_CREAT

mode :文件权限,常用06666

value:信号量值。二元信号量值为1,普通表示资源数目;

信号灯文件为止:/dev/shm/

有名信号灯关闭:

int sem_close(sem_t *sem);

有名信号灯的删除:

int sem_unlink(const char* name);

代码实现:

mysem_w:

#include <stdio.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <signal.h>

void delsemfile(int sig) {
	sem_unlink("mysem_w");
	exit(0);
}

int main() {

//捕捉信号,按下Ctrl+c时删除myser_w
	struct sigaction act;
	act.sa_handler = delsemfile;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);

	sigaction(SIGINT, &act, NULL);

//创建共享内存

	//1 申请共享内存key值;
    key_t key;
	key = ftok(".", 100);
	if (key < 0) {
		perror("ftok");
		return 0;
	}

	//2 根据key值创建共享内存
    int shmid;
	shmid = shmget(key, 500, 0666|IPC_CREAT);
	if (shmid < 0) {
		perror("shmget");
		return 0;
	}

	//3 获取共享内存地址
    char *shmaddr;
	shmaddr = shmat(shmid, NULL, 0);

	//定义读写信号量
    sem_t *sem_r, *sem_w;

	//打开信号量;(初始化 读信号量为0,写信号量为1)
	sem_r = sem_open("mysem_r", O_CREAT|O_RDWR, 0666, 0);
	sem_w = sem_open("mysem_w", O_CREAT|O_RDWR, 0666, 1);

//向共享内存中写数据

	//1 判断是否能写
	while(1) {
		sem_wait(sem_w);    //sem_w--
		printf(">");
		fgets(shmaddr, 500, stdin);
		sem_post(sem_r);    //sem_r++
	}



}

 mysem_r:

#include <stdio.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <signal.h>

void delsemfile(int sig) {
	sem_unlink("mysem_r");
	exit(0);
}


int main() {

//捕捉信号,按下Ctrl+c时删除myser_r
	struct sigaction act;
	act.sa_handler = delsemfile;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);

	sigaction(SIGINT, &act, NULL);

//创建共享内存

	//1 申请共享内存key值;
    key_t key;
	key = ftok(".", 100);
	if (key < 0) {
		perror("ftok");
		return 0;
	}

	//2 根据key值创建共享内存
    int shmid;
	shmid = shmget(key, 500, 0666|IPC_CREAT);
	if (shmid < 0) {
		perror("shmget");
		return 0;
	}

	//3 获取共享内存地址
    char *shmaddr;
	shmaddr = shmat(shmid, NULL, 0);

	//定义读写信号量
    sem_t *sem_r, *sem_w;

	//打开信号量;(初始化 读信号量为0,写信号量为1)
	sem_r = sem_open("mysem_r", O_CREAT|O_RDWR, 0666, 0);
	sem_w = sem_open("mysem_w", O_CREAT|O_RDWR, 0666, 1);

//向共享内存中写数据

	//1 判断是否能写
	while(1) {
		sem_wait(sem_r);    //sem_r--

		printf("%s\n", shmaddr);

		sem_post(sem_w);    //sem_w++
	}



}

无名信号灯

无名信号灯在Linux下只支持线程间同步不支持进程间同步

无名信号灯的初始化

int sem_close(sem_t *sems, int shared, unsigned int value);

参数:

sem:需要初始化的信号灯变量;

shared:shared指定为0,表示信号量只能由这个初始化这个信号量的进程使用,不能在进程间使用,Linux不支持进程间同步;

value:信号量的值

无名信号灯的销毁:

int sem_destroy(sem_t *sem);

信号灯P操作

int sem_wait(sem_t *sem);

获取资源,如果信号量为0,表示这时没有相应资源空闲,那么调用线程就将挂起,直到有空闲资源可以获取

信号灯V操作

int sem_post(sem_t *sem);

释放资源,如果没有线程阻塞在该sem上,表示没有线程等待该资源,这时该函数就对信号量的值进行增1操作,表示同类资源多增加了一个。如果至少有一个线程阻塞在该sem上,表示有线程等待资源,信号量为0,这时该函数保持信号量为0不变,并使某个阻塞在该sem上的线程从sem_wait函数中返回

注意:编译posix信号灯需要加pthread动态库。

代码实现

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#include <pthread.h>

sem_t sem_r, sem_w;
char *shmaddr;

void deseroysem(int sig) {
	sem_destroy(&sem_r);
	sem_destroy(&sem_w);
	exit(0);
}

void *readmem(void *arg) {
	while(1) {
		sem_wait(&sem_r);
		printf("%s\n", shmaddr);
		sem_post(&sem_w);
	}
}

int main() {

//捕捉信号,按下Ctrl+c时删除myser_w
	struct sigaction act;
	act.sa_handler = deseroysem;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);

	sigaction(SIGINT, &act, NULL);

//创建共享内存

	//1 申请共享内存key值;
	key_t key;
	key = ftok(".", 100);
	if (key < 0) {
		perror("ftok");
		return 0;
	}

	//2 根据key值创建共享内存
	int shmid;
	shmid = shmget(key, 500, 0666|IPC_CREAT);
	if (shmid < 0) {
		perror("shmget");
		return 0;
	}

	//3 获取共享内存地址
	shmaddr = shmat(shmid, NULL, 0);
	
	//无名信号灯初始化;
	sem_init(&sem_r, 0, 0);
	sem_init(&sem_w, 0, 1);

	//创建线程
	pthread_t tid;
	pthread_create(&tid, NULL, readmem, NULL);

	//向共享内存中写数据
	while(1) {
		sem_wait(&sem_w);    //sem_w--
		printf(">");
		fgets(shmaddr, 500, stdin);
		sem_post(&sem_r);    //sem_r++
	}



}

system V信号灯的

int semget*key_t key, int nsems, int semflg);

功能:创建 / 打开信号灯;

参数:

key:ftok 产生的key值;(和信号灯关联的key值)

nsems :信号灯集 中包含的信号灯数目;

semflg :信号灯集 的访问权限,通常是IPC_CREAT | 0666

返回值:成功返回信号灯集id, 失败返回-1;

int semop(int semid, struct sembuf *opsptr, size_t nops);

功能:对信号灯集合中的信号量进行p  -  v操作

参数:

semid:信号灯集合 的id;

struct sembuf {

                short sem_num;         //要操作的信号灯的编号;

                short sem_op;            //1:释放资源,V操作; -1:分配资源, P操作;

                short sem_flg;            // 0(阻塞),IPC_NOWAT,SEM_UNDO

};                               //对某一个信号灯的操作,如果同时对多个操作,则需要定义这种结构以数组

nops:要操作的信号灯的个数, 1个;

返回值:成功:0,; 失败:-1.

int semctl(int semid, int semnum, int cmd.../*union semun arg*/);

功能:信号灯集合的控制(初始化 / 删除)

参数:

semid:信号灯集id

semnum: 要操作的集合中的信号灯编号

   cmd:

   GETVAL:获取信号灯的值,返回值是获得值

   SETVAL:设置信号灯的值,需要用到第四个参数:共用体

   IPC_RMID:从系统中删除信号灯集合

返回值:成功 0 ; 失败 -1

代码实现:

#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>

#define SEM_READ 0
#define SEM_WRITE 1

union semun{
	int val;
};

//p操作
void Poperation(int semid, int semindex) {
	struct sembuf sbuf;
	sbuf.sem_num = semindex;
	sbuf.sem_op = -1;
	sbuf.sem_flg = 0;

	semop(semid, &sbuf, 1);


}
//v操作
void Voperation(int semid, int semindex ) {

	struct sembuf sbuf;
	sbuf.sem_num = semindex;
	sbuf.sem_op = 1;
	sbuf.sem_flg = 0;

	semop(semid, &sbuf, 1);

}



int main() {
	key_t key;
	int semid;
	int shmid;
	char *shmaddr;

	key = ftok(".", 100);
	if (key < 0) {
		perror("ftok");
		return 0;
	}

	semid = semget(key, 2, IPC_CREAT|0666);
	if (semid < 0) {
		perror("semget");
		return 0;
	}

	shmid = shmget(key, 500, IPC_CREAT|0666);
	shmaddr = shmat(shmid, NULL, 0);

	//初始化
	union semun mysem;
	mysem.val = 0;
	semctl(semid, SEM_READ, SETVAL, mysem);
	mysem.val = 1;
	semctl(semid, SEM_WRITE, SETVAL, mysem);


	pid_t pid;
	pid = fork();
	if (pid < 0) {
		perror("fork");
		shmctl(shmid, IPC_RMID, NULL);
		semctl(semid, 0, IPC_RMID);
		exit(-1);
	}else if(pid == 0) {
		while(1){
			Poperation(semid, SEM_READ);

			printf("%s\n", shmaddr);

			Voperation(semid, SEM_WRITE);
		}

	}else{
		while(1){
			Poperation(semid, SEM_WRITE);

			printf(">");
			fgets(shmaddr, 32, stdin);

			Voperation(semid, SEM_READ);
		} 
	}


}

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

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

相关文章

【C语言】程序运行环境及预处理指令

文章目录 程序的翻译环境&#xff1a;程序的运行环境&#xff1a;C语言预定义符号#define定义标识符#define定义宏具有副作用的宏参数 #与###的使用##的使用 宏和函数对比#undef命令行定义条件编译常见的条件编译指令&#x1f31e; 文件包含指令嵌套文件包含 其他预处理指令 撒…

【C++】对数组指针的理解,例如 int (*p)[3]

目录 简介思考理解结语 简介 Hello&#xff01; 非常感谢您阅读海轰的文章&#xff0c;倘若文中有错误的地方&#xff0c;欢迎您指出&#xff5e; ଘ(੭ˊᵕˋ)੭ 昵称&#xff1a;海轰 标签&#xff1a;程序猿&#xff5c;C选手&#xff5c;学生 简介&#xff1a;因C语言结识…

Win7 无法安装 VMware Tools 解决方法

文章目录 1.下载kb4474419补丁2.虚拟机 > 设置 > 软盘&#xff0c;选中“使用物理驱动器”3.解决IE浏览器只能访问百度4.下载windows iso的正确方式 win7版本&#xff1a;cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408_2&#xff08;iso大小3.18 GB&#xff09; vmwa…

C++内联函数(编译器角度,汇编角度),auto关键字,范围for语法糖,nullprt与NULL区别等

TIPS 在C当中有一个东西可以打印类型&#xff1f;typeid(变量名).name()数组一旦从参数进入到函数里面&#xff0c;它就已经是个指针了&#xff0c;再也不是一整个数组了 内联函数&#xff08;正常函数定义前加个inline修饰&#xff09; 在实际当中&#xff0c;有时候去调用…

13、拦截器

文章目录 1、HandlerInterceptor 接口2、配置拦截器3、拦截器原理 【尚硅谷】SpringBoot2零基础入门教程-讲师&#xff1a;雷丰阳 笔记 路还在继续&#xff0c;梦还在期许 1、HandlerInterceptor 接口 /*** 登录检查* 1、配置好拦截器要拦截哪些请求* 2、把这些配置放在容器中…

爬虫——肯德基

import requests #UA伪装&#xff1a;将对应的User-Agent封装到一个字典中 headers{User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48 } #指定url url http://www.kfc.com.c…

【jvm系列-09】垃圾回收底层原理和算法以及JProfiler的基本使用

JVM系列整体栏目 内容链接地址【一】初识虚拟机与java虚拟机https://blog.csdn.net/zhenghuishengq/article/details/129544460【二】jvm的类加载子系统以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963【三】运行时私有区域之虚拟机栈…

一图看懂 xlrd 模块:读写 Excel 文件的数据和格式信息, 资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 xlrd 模块&#xff1a;读写 Excel 文件的数据和格式信息, 资料整理笔记&#xff08;大全&#xff09; 摘要模块图类关系图模块全展开【xlrd】统计常量intdict 模块26 os27 …

【蓝桥杯省赛真题19】python完数及个数 青少年组蓝桥杯python编程省赛真题解析

目录 python完数及个数 一、题目要求 1、编程实现 2、输入输出 二、解题思路

itop-3568开发板驱动学习笔记(22)设备树(一)设备树基础

《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 文章目录 设备树简介设备树编译设备树语法设备根节点设备子节点节点名称reg 属性#address-cell 和 #size-cells 属性model 属性status 属性compatible 属性aliases 节点chosen 节点device_type 属性自定义属性 设备树…

使用Docker创建并运行Jenkins详细步骤

文章目录 一、使用Docker搭建Jenkins二、为Jenkins配置执行节点1、进入管理页面2、新建节点3、配置节点信息4、子节点连接master节点5、在子节点机器上运行上面复制下来的命令6、查看子节点是否在线 三、创建一个简单的job1、进入创建页面2、设置job名称3、配置job相关信息4、构…

eBay变现方式有哪些?如何利用好测评自养号?

近年来&#xff0c;越来越多的人选择在eBay开店&#xff0c;甚至很多其他平台的卖家也转型到了eBay。但很多卖家发现&#xff0c;在运营了一段时间后&#xff0c;过了对新账号的流量扶持期&#xff0c;店铺突然出现流量开始下滑的情况&#xff0c;针对这种情况卖家可以采取哪些…

计算机网络(数据链路层)部分习题

1. 通过传统以太网发送中文“华南师范大学计算机学院”&#xff0c;封装成以太网帧&#xff0c;请问该帧的数据字段有效字节是多少&#xff1f;需要填充多少个字节&#xff1f; 答&#xff1a;一个字两个字节&#xff0c;“华南师范大学计算机学院”共11个字&#xff0c;有效字…

Visual Studio容器工具要求在构建,调试或运行容器化项目之前运行Docker

出现此提示&#xff0c;是因为电脑未安装Docker所致&#xff0c;接下来就教大家如何安装Docker。 第一步&#xff1a;下载 地址&#xff1a;Install Docker Desktop on Windows | Docker Documentation 第二步&#xff1a;安装 1、双击Docker Desktop Installer.exe运行安装程…

电子束与材料相互作用Matlab代码

标题 1 题目2 实验原理2.1 蒙特卡洛模拟的基本思想2.2 电子散射的基本概念 3 代码 1 题目 扫描透射电镜(STEM)的基本原理是用极细的扫描电子束透射样品,透射电子直接被具有一定张角的接收器所接收&#xff0c;透射电流的强度直接反应了样品的质量厚度。 对于一定厚度的样品&am…

面试官:一千万的数据,你是怎么查询的?

面试官&#xff1a;一千万的数据&#xff0c;你是怎么查询的&#xff1f; 1 先给结论 对于1千万的数据查询&#xff0c;主要关注分页查询过程中的性能 针对偏移量大导致查询速度慢&#xff1a; 先对查询的字段创建唯一索引 根据业务需求&#xff0c;先定位查询范围&#xff08…

23Java面试专题 八股文面试全套真题(含大厂高频面试真题)

准备篇-01-企业简历筛选规则 准备篇-02-简历注意事项 等写简历的时候看02和04... 准备篇-03-应届生该如何找到合适的练手项目 &#xff01;准备篇-04-Java程序员的面试过程 Redis篇-01-redis开篇 感觉有点难 Redis篇-02-redis使用场景-缓存-缓存穿透 Redis篇-03-redis使用场景-…

一日一题:第十题---并查集(集合合并)and 二叉树遍历

​作者&#xff1a;小妮无语 专栏&#xff1a;一日一题 &#x1f6b6;‍♀️✌️道阻且长&#xff0c;不要放弃✌️&#x1f3c3;‍♀️ 今天来更前几天做的&#xff0c;怕忘记了hh 目录 并查集题目描述(集合合并)代码对路径压缩的解释 二叉树遍历题目描述代码 并查集 ​​​…

【JavaEE】死锁是什么?如何避免死锁(保姆级讲解)

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 本篇文章将介绍什么是死锁&#xff0c;死锁的四大必要条件&#xff0c;如何去避免死锁~~~ 目录 一、死锁是什么&#xff1f; 二、关于死锁的情况 2.1 一个线程的情况 2.2 两个线程的情…

javaweb家具购物商城的电商设计与实现

目 录 1 绪论 1 1.1 项目背景 1 1.2 研究意义 1 1.3 本系统概述 2 2系统分析 3 2.1 系统需求分析 3 2.1.1 功能需求 3 2.1.2 性能需求 4 2.2 系统可行性分析 4 2.2.1 技术及开发方法可行性 4 2.2.2 管理可行性 4 2.2.3 经济可行性 5 2.3 业…