lv5 嵌入式开发-12 信号灯

目录

1 信号量/灯(semaphore)基本概念

2 信号量-P/V操作概念

3 三种信号灯

3.1 有名信号灯

3.1.1 打开

3.1.2 关闭

3.1.3 删除

3.2 无名信号灯

3.2.1 初始化

3.2.2 销毁

3.3 信号灯P操作

3.4 信号灯V操作

3.5 示例

3.5.1 有名信号示例

3.5.2 无名信号灯示例(逻辑同上)

3.5 System V 信号灯使用:

3.5.1 创建/打开信号灯

3.5.2 进行P - V操作

3.5.3 初始化/删除

3.5.4 System V IPC - 信号灯特点

3.5.5  System V信号灯使用步骤

3.6 System V信号灯示例


掌握:信号灯机制、信号灯初始化、打开/创建信号灯、信号灯-P操作、信号灯-V操作、信号灯、共享内存

1 信号量/灯(semaphore)基本概念

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

概念:是不同进程间或一个给定进程内部不同线程间同步的机制。类似我们的生产者和消费者场景。

类似之前讲过的条件变量。

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

  •         初始化
  •         P操作(申请资源)
  •        V操作(释放资源)

2 信号量-P/V操作概念

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

3 三种信号灯

信号灯也叫信号量,用于进程/线程同步或互斥的机制

信号灯的类型  

  • Posix 无名信号灯  
  • Posix有名信号灯    (linux只支持线程同步)
  • System V  信号灯

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

wait 相当于p操作,post相当于v操作 

3.1 有名信号灯

3.1.1 打开

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:文件权限。常用0666

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

信号灯文件位置:/dev/shm

3.1.2 关闭

int sem_close(sem_t *sem);

3.1.3 删除

int sem_unlink(const char* name);

3.2 无名信号灯

3.2.1 初始化

int sem_init(sem_t *sem, int shared, unsigned int value);

 参数:

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

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

Value:信号量的值

3.2.2 销毁

int sem_destroy(sem_t* sem);

成功时返回0,失败时返回EOF  

sem  指向要操作的信号量对象

3.3 信号灯P操作

int sem_wait(sem_t *sem);

成功时返回0,失败时返回EOF  

sem  指向要操作的信号量对象

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

3.4 信号灯V操作

int sem_post(sem_t *sem);

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

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

3.5 示例

3.5.1 有名信号示例

避免读写混乱:规定写资源初值为1,读资源初值为0。获取写入权限,后写-1,读+1,获取读权限后,读-1,写+1。

sem_r.c

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>//删除信号,以免程序退出(ctrl+c) 重新打开无法开启
void delsemfile(int sig){sem_unlink("mysem_r");exit(0);
}int main(){sem_t *sem_r,*sem_w;key_t key;int shmid;char *shmaddr;struct sigaction act;act.sa_handler = delsemfile;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(SIGINT,&act,NULL); //启用linux中信号退出回调函数delsemfile,用于删除信号量key = ftok(".",100);if(key<0){perror("ftok");   return 0;}shmid = shmget(key,500,0666|IPC_CREAT);  //创建信号灯if(shmid<0){perror("shmget");return 0;}shmaddr = shmat(shmid,NULL,0);           //创建共享内存sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);   //创建初值为0的读信号灯sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);   //创建初值为1的写信号灯while(1){sem_wait(sem_r);             //P操作,获取读资源,读资源-1printf("%s\n",shmaddr);sem_post(sem_w);             //V操作,写资源+1}
}

sem_w.c

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>void delsemfile(int sig){sem_unlink("mysem_w");exit(0);
}int main(){sem_t *sem_r,*sem_w;key_t key;int shmid;char *shmaddr;struct sigaction act;act.sa_handler = delsemfile;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(SIGINT,&act,NULL);key = ftok(".",100);if(key<0){perror("ftok");return 0;}shmid = shmget(key,500,0666|IPC_CREAT);  //创建信号灯,500个字节if(shmid<0){perror("shmget");return 0;}shmaddr = shmat(shmid,NULL,0);sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);while(1){sem_wait(sem_w);printf(">");fgets(shmaddr,500,stdin);sem_post(sem_r);}}

3.5.2 无名信号灯示例(逻辑同上)

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#include <pthread.h>sem_t sem_r,sem_w;
char *shmaddr;void destroysem(int sig){
//    sem_unlink("mysem_w");sem_destroy(&sem_r);sem_destroy(&sem_w);exit(0);}void *readmem(void *arg){while(1){sem_wait(&sem_r);         //P操作printf("%s\n",shmaddr);sem_post(&sem_w);         //V操作}}int main(){key_t key;int shmid;struct sigaction act;act.sa_handler = destroysem;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(SIGINT,&act,NULL);key = ftok(".",100);if(key<0){perror("ftok");return 0;}shmid = shmget(key,500,0666|IPC_CREAT);if(shmid<0){perror("shmget");return 0;}shmaddr = shmat(shmid,NULL,0);//   sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0);
//   sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1);sem_init(&sem_r,0,0);     //有名信号灯创建,读初值0sem_init(&sem_w,0,1);     //有名信号灯创建,写初值1pthread_t tid;pthread_create(&tid,NULL,readmem,NULL);   //创建线程while(1){sem_wait(&sem_w);    //P操作printf(">");fgets(shmaddr,500,stdin);sem_post(&sem_r);    //V操作}}

3.5 System V 信号灯使用:

3.5.1 创建/打开信号灯

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

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

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

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

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

3.5.2 进行P - V操作

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

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

参数:semid:信号灯集ID        

          opsptr:   操作结构体

struct sembuf {short sem_num; // 要操作的信号灯的编号short sem_op;  // 1 : 释放资源,V操作// -1 : 分配资源,P操作  short sem_flg; // 0(阻塞),IPC_NOWAIT, SEM_UNDO
};//对某一个信号灯的操作,如果同时对多个操作,则需要定义这种结构体数组

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

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

3.5.3 初始化/删除

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

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

参数:semid:信号灯集ID

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

           cmd:

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

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

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

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

3.5.4 System V IPC - 信号灯特点

System V 信号灯是一个或多个计数信号灯的集合

可同时操作集合中的多个信号灯

申请多个资源时避免死锁

3.5.5  System V信号灯使用步骤

  • 打开/创建信号灯  
  • semget 信号灯初始化  
  • semctl P/V操作   semop
  • 删除信号灯  semctl

3.6 System V信号灯示例

#include <semaphore.h>
#include <stdio.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  1union semun {int val;
};               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);}
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;char *shmaddr;int semid,shmid;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.mzph.cn/news/91901.shtml

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

相关文章

Visual Studio 中将TAB设置为空格

将TAB设置为空格的原因很多&#xff0c;其中一点是为了统一不同编译器对TAB的解释&#xff0c;防止代码风格在不同编译器下不一致等。 在菜单中选择: 工具-->选项-->文本编辑器--->所有语言-->制表符 在窗口中选择&#xff0c;制表符大小和缩进大小都选为4&#xf…

10.1 国庆节小任务

目录 select实现服务器并发 服务器 客户端 运行现象 select实现服务器并发 服务器 #include<myhead.h>#define PORT 8888 //1024~49151 #define IP "192.168.1.104" //ifconfig查看本机IPint main(int argc, const char *argv[]) {//创建流式…

本次CTF·泰山杯网络安全的基础知识部分(二)

简记23年九月参加的泰山杯网络安全的部分基础知识的题目&#xff0c;随时补充 15&#xff08;多选&#xff09;网络安全管理工作必须坚持“谁主管、谁负责&#xff0c;谁运营、谁负责&#xff0c;谁使用、谁负责”的原则&#xff0c;和“属地管理”的原则 谁主管、谁负责&…

WiFi网络分析工具Airtool for Mac

Airtool是一款Mac平台上的WiFi网络分析工具&#xff0c;它可以帮助用户监测、分析和管理无线网络。 以下是Airtool的一些主要功能和特点&#xff1a; 实时监测&#xff1a;Airtool可以实时监测当前Mac设备所连接的WiFi网络&#xff0c;包括网络速度、信号强度、连接状态等。信…

Greenplum 对比 Hadoop

Greenplum属于MPP架构&#xff0c;和Hadoop一样都是为了解决大规模数据的并行计算而出现的技术&#xff0c;两者的相似点在于&#xff1a; 分布式存储&#xff0c;数据分布在多个节点服务器上分布式并行计算框架支持横向扩展来提高整体的计算能力和存储容量都支持X86开放集群架…

8、表格标签

8、表格标签 一、为什么使用表格 简单通用结构稳定 二、基本结构 &#xff08;一&#xff09;单元格 &#xff08;二&#xff09;行 行的英语是rows所以&#xff0c;行就用tr表示 &#xff08;三&#xff09;列 使用td表示 &#xff08;四&#xff09;跨行 &#xff…

蓝桥等考Python组别九级002

第一部分:选择题 1、Python L9 (15分) 运行下面程序,可以输出几行“*”?( ) for i in range(5): for j in range(6): print(*, end = ) print() 3456正确答案:C 2、Python L

Spark SQL

Spark SQL 一、Spark SQL概述二、准备Spark SQL的编程环境三、Spark SQL程序编程的入口四、DataFrame的创建五、DataFrame的编程风格六、DataSet的创建和使用七、Spark SQL的函数操作 一、Spark SQL概述 Spark SQL属于Spark计算框架的一部分&#xff0c;是专门负责结构化数据的…

运算符 - Go语言从入门到实战

运算符 - Go语言从入门到实战 算术运算符 假设A变量等于10&#xff0c;B变量等于20。 运算符描述实例相加A B 输出结果 30-相减A - B 输出结果 -10*相乘A * B 输出结果 200/相除B / A 输出结果 2%求余B % A 输出结果 0⾃增A 输出结果 11–⾃减A-- 输出结果 9 特性&#xf…

NIO基础

nio : non-blocking io 非阻塞IO 1. 三大组件 1.1 channel和buffer channel 有点像stream &#xff0c;他就是读写数据的双向通道&#xff0c;可以从channel将数据读入buffer&#xff0c;也可以将buffer的数据写入channel&#xff0c;之前的stream 要么输入&#xff0c;要么…

建筑能源管理(3)——建筑能源监管

为了全面落实科学发展观&#xff0c;提高建筑能源管理水平&#xff0c;进一步降低能源和水资源消耗、合理利用资源&#xff0c;以政府办公建筑和大型公共建筑的运行节能管理为突破口&#xff0c;建立了既有政府办公建筑和大型公共建筑运行节能监管体系&#xff0c;旨在提高政府…

【bug 记录】yolov5_C_demo 部署在 rv1126

问题1&#xff1a;opencv find 不到 在 CMakeLists 中将正确的 OpenCV库 路径添加到 CMAKE_PREFIX_PATH 变量中 set(CMAKE_PREFIX_PATH “/mnt/usr/local” ${CMAKE_PREFIX_PATH}) 问题2&#xff1a; rknn_api.h 找不到 将该文件从别处复制到项目 include 文件夹 问题3&…

28271-2012 米制超细牙螺纹 公差

声明 本文是学习GB-T 28271-2012 米制超细牙螺纹 公差. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了米制超细牙螺纹的公差和标记。 本标准适用于精密仪器和电子设备等领域的螺纹连接。 2 规范性引用文件 下列文件对于本文件…

windows server 2019 、win11安装docker desktop

Docker Desktop Docker Desktop是可以部署在windows运行docker的应用服务&#xff0c;其基于windos的Hyper-V服务和WSL2内核在windos上创建一个子系统(linux)&#xff0c;从而实现其在windows上运行docker。 前提条件 WSL 查看wsl是否安装 我们可以直接在 cmd 或 powershe…

vue3中的watch

在Vue3中&#xff0c;watch中的参数可以分为两部分&#xff0c;即要监听的响应式数据以及回调函数。 语法格式如下&#xff1a; watch(要监听的响应式数据, 回调函数)除了以上的两个还有其他的参数 immediate&#xff1a;是否在初始化时立即执行一次回调函数&#xff0c;默认…

MySql出错点

一、DDL 1.修改表&#xff0c;添加新的字段时&#xff0c;不要加引号 2.在修改表中字段的类型时&#xff0c;会发生数据截断。 像DATETIME 转化为 TIME 二、DML 1.插入和删除的注意点 2.可以通过 select 来协助插入 3.

Linux 基本语句_4_指针和函数

指针函数 顾名思义&#xff0c;即返回值为指针的函数 int * f (int n){int *p NULL;//空指针return p;//返回一个地址 }函数指针 指向函数的指针&#xff0c;每个函数都有自己的入口地址&#xff0c;函数指针专门指向这些地址#include <stdio.h>int max(int a, int b)…

【Linux】完美解决ubuntu18.04下vi不能使用方向键和退格键

今天在刚安装完ubuntu18.04&#xff0c;发现在使用vi命令配置文件时使用方向键并不能移动光标&#xff0c;而是出现一堆奇怪的英文字母&#xff0c;使用退格键也不能正常地删除内容&#xff0c;用惯了CentOS的我已经感觉到ubuntu没有centos用着丝滑&#xff0c;但是没办法&…

【C++】类和对象(中)

一、类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。但是空类中并不是真的什么都没有&#xff0c;任何类在什么都不写的时候&#xff0c;编译器会自动生成以下 6 个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器会生成…

5G消息发展的前景与挑战

随着5G技术的快速发展和普及&#xff0c;5G消息正逐渐成为全球通信领域的新焦点。 随着5G技术的快速发展和普及&#xff0c;5G消息正逐渐成为全球通信领域的新焦点。 5G消息发展呈现规模化、产业化趋势 自2020年4月国内三大运营商联合发布5G消息白皮书以来&#xff0c;已经过…