Linux系统编程——信号量

一、信号量的定义和原理

1、概念

  • 原子操作:不可中断的一个或者一系列的操作,即一件事要么做要么不做。
  • 临界资源:不同进程能够看到的一份公共资源,一次只能被一个进程使用。
  • PV操作:由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

                P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行;
                V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1。


  就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

2、信号量的定义

  为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。

3、信号量的原理

1. 测试控制该资源的信号量;

2. 若信号量的值为正,则进程可以使用该资源,进程的信号量值减1,表示一个资源被使用;

3. 若此信号量为0,则进程进入休眠,直到该信号量值大于0;

4. 当进程不再使用一个由一个信号控制的共享资源时,该信号量加1,如果有进程正在休眠等待该信号量,则该进程会被唤醒。

二、信号量的使用

1、一些数据结构的定义

(1)semid_ds

  内核为每个信号量集合维护着一个结构体:

struct semid_ds{struct ipc_perm sem_perm;unsigned short sem_nsems;time_t sem_otime;time_t sem_ctime;...
}

(2)semun(必须定义该联合体)

union semun{int             val;struct semid_ds *buf;unsigned short  *array;
}

(3)sembuf(信号量操作数组)

struct sembuf{// 除非使用一组信号量,否则它为0,一般从0,1,...num_secs-1unsigned short    sem_num; // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,// 即P(等待)操作,一个是+1,即V(发送信号)操作。short             sem_op;// 通常为SEM_UNDO,使操作系统跟踪信号,// 并在进程没有释放该信号量而终止时,操作系统释放信号量。short              sem_flg;
}

2、semget函数

#include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);

功能:创建一个新信号量集或取得一个已有信号量集。
参数
        key:整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget函数并提供一个键,再由系统生成一个相应的信号标识符(semget函数的返回值),只有semget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作;
        num_sems:指定需要的信号量数目,它的值几乎总是1;
        sem_flags:一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。
        返回值:成功返回一个相应信号标识符(非零),失败返回-1。

3、semop函数

#include <sys/sem.h>
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

功能:它的作用是改变信号量的值。
参数
        sem_id:由semget返回的信号量标识符;
        sem_opa:表示一个由sembuf结构表示的信号量操作数组;
        num_sem_ops:规定该数组中操作的数量。
返回值:成功返回0,失败返回-1。

4、semctl函数

#include <sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);

功能:直接控制信号量的信息。
参数
        sem_id:信号量标识符;
        sem_num:信号量的值;
        command:通常是下面两个值中的其中一个:
        SETVAL:用来把信号量初始化为一个已知的值。p 这个值通过union semun中的val成员设置,其作用是在信号量第一次使用前对它进行设置;
        IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。
返回值:成功返回0,失败返回-1。

三、信号量的demo

// comm.h
#ifndef _MYSEM_H_
#define _MYSEM_H_#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>  // ftok
#include <sys/sem.h>
#include <sys/wait.h>
#include <string.h>#define PATHNAME "."  // ftok 中生成key值 . 表示当前路径
#define PROJ_ID  56  // ftok 中配合PATHNAME 生成唯一key值union semun
{int val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf;
};int create_sems(int nums);  // 创建含有nums个信号量的集合
int get_sems();     // 获取信号量
// 初始化semid对应的信号量集中编号为which的信号量值为value
int init_sems(int semid , int which, int value);
int destroy_sems(int semid); // 释放该信号量集
int P(int semid, int which);    // 表示分配 信号量值-1
int V(int semid, int which);    // 表示释放 信号量值+1#endif /* _MYSEM_H_ */
// comm.cpp
#include "comm.h"// 创建信号量和获取信号量公用函数
static int comm_sem(int nums , int semflag)
{// ftok 函数把一个已存在的路径名和一个整数标识转换成一个key_t值,// 即IPC关键字。key_t key = ftok(PATHNAME, PROJ_ID);if(key < 0){perror("ftok");return -1;}// 用来创建一个信号集,或者获取已存在的信号集。int semid = semget(key, nums, semflag); if( semid < 0){perror("semget");return -1;}return semid;
}// 初始化操作数组
static int comm_sem_op(int semid, int which, int op)
{struct sembuf _sembuf;_sembuf.sem_num = which;_sembuf.sem_op = op;_sembuf.sem_flg = 0; //  IPC_NOWAIT  SEM_UNDOreturn semop(semid, &_sembuf, 1);
}// 创建含有nums个信号量的集合
int create_sems(int nums)
{return comm_sem(nums, IPC_CREAT|IPC_EXCL|0666);
}// 初始化信号集
int init_sems(int semid , int which, int value)
{union semun _semun;_semun.val = value;int ret = semctl(semid, which, SETVAL,_semun);if(ret < 0){perror("inin_sem");return -1;}return 0;
}// 获取信号量
int get_sems()    
{return comm_sem(0, IPC_CREAT);
}// 释放该信号量集
int destroy_sems(int semid) 
{int ret = semctl(semid, 0, IPC_RMID, NULL);if(ret < 0){perror("rm_sem");return -1;}return 0;
}// P操作
int P(int semid, int which)    
{return comm_sem_op(semid, which , -1);
}// V操作
int V(int semid, int which)    
{return comm_sem_op(semid, which, 1);
}
// test.cpp
#include "comm.h"
#include <stdio.h>
#include <unistd.h>int main()
{int semid = create_sems(10); // 创建一个包含10个信号量的信号集init_sems(semid, 0, 1);  // 初始化编号为 0 的信号量值为1pid_t id = fork(); // 创建子进程if (id < 0){perror("fork");return -1;}else if (0 == id) // 子进程{ int sem_id = get_sems();while(1){P(sem_id, 0); // 对该信号量集中的0号信号做P操作printf("你");fflush(stdout);sleep(1);printf("好");printf(":");fflush(stdout);sleep(1);V(sem_id, 0);}}else // 父进程{while(1){P(semid,0);printf("在");sleep(1);printf("吗");printf("?");fflush(stdout);V(semid, 0);}wait(NULL);}destroy_sems(semid);return 0;
}

四、信号量的总结

  信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。我们经常通过信号来解决多个进程对同一资源的访问竞争的问题,使在任一时刻只能有一个执行线程访问代码的临界区域,也可以说它是协调进程间的对同一资源的访问权,也就是用于同步进程的。

【优点】:可以同步进程。
【缺点】:信号量有限。

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

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

相关文章

QT项目-仿QQ聊天(带宠物系统)

目录 一&#xff0c;项目介绍 二&#xff0c;开发环境 三&#xff0c;涉及技术 四&#xff0c;项目效果示例图 1&#xff0c;登录界面 2&#xff0c;主界面 3&#xff0c;聊天界面 4&#xff0c;功能界面 5&#xff0c;宠物界面 一&#xff0c;项目介绍 这是一个基于u…

vue打包项目通过docker部署nginx服务

一、构建前端代码 npm install nmp run build 确认自己的打包路径&#xff0c;默认是dist&#xff0c;这里也可以修改。 二、将打包的项目使用dockerfile构建 dockerfile 将dist文件复制到nginx的指定的路径&#xff0c;前端界面的路径&#xff0c;还需要两个conf文件 FR…

数据分析与效果评估的有效方法与实践探讨

内容概要 在现代社会中&#xff0c;数据分析与效果评估已成为各类项目管理和决策制定中的重要组成部分。首先&#xff0c;数据分析为我们提供了一种系统化的方法&#xff0c;以深入了解所收集数据的内涵与趋势。通过对数据进行整理、分类和分析&#xff0c;我们能够发现潜在的…

【Kettle的安装与使用】使用Kettle实现mysql和hive的数据传输(使用Kettle将mysql数据导入hive、将hive数据导入mysql)

文章目录 一、安装1、解压2、修改字符集3、启动 二、实战1、将hive数据导入mysql2、将mysql数据导入到hive 一、安装 Kettle的安装包在文章结尾 1、解压 在windows中解压到一个非中文路径下 2、修改字符集 修改 spoon.bat 文件 "-Dfile.encodingUTF-8"3、启动…

2024年NSSCTF秋季招新赛-WEB

The Beginning F12看源码&#xff0c;有flag http标头 黑吗喽 题目说要在发售时的0点0分&#xff0c;所以添加标头data Date: Tue, 20 Aug 2024 00:00:00 GMT然后改浏览器头 User-Agent: BlackMonkey曲奇就是Cookie cookieBlackMonkey这个一般就是Referer Referer:wukon…

【Python单元测试】pytest框架单元测试 配置 命令行操作 测试报告 覆盖率

单元测试&#xff08;unit test&#xff09;&#xff0c;简称UT。本文将介绍在Python项目中&#xff0c;pytest测试框架的安装&#xff0c;配置&#xff0c;执行&#xff0c;测试报告与覆盖率 pytest简介 pytest是一款流行的&#xff0c;简单易上手的单元测试框架&#xff0c;…

python之数据结构与算法(数据结构篇)-- 集合

一、集合的概念 所谓的编程中的”集合“&#xff0c;其实和高中数学中集合是一样的的。比如&#xff1a;羊村和狼堡分别看作两个集合&#xff0c;而狼堡中的"灰太狼"、"红太狼"、"小灰灰"则可看作狼堡中的元素&#xff0c;同理&#xff0c;羊村…

C# 企业微信机器人推送消息 windows服务应用程序的使用

C# 企业微信机器人推送消息 先添加一个机器人! 然后查看机器人就可以得到一个 webhook 特别特别要注意&#xff1a;一定要保护好机器人的webhook地址&#xff0c;避免泄漏&#xff01; 然后开始写代码 &#xff0c;只需要httpPost 调用一下这个地址就可以发送消息了。 首先我…

「Mac畅玩鸿蒙与硬件14」鸿蒙UI组件篇4 - Toggle 和 Checkbox 组件

在鸿蒙开发中,Toggle 和 Checkbox 是常用的交互组件,分别用于实现开关切换和多项选择。Toggle 提供多种类型以适应不同场景,而 Checkbox 支持自定义样式及事件回调。本篇将详细介绍这两个组件的基本用法,并通过实战展示它们的组合应用。 关键词 Toggle 组件Checkbox 组件开…

基于SpringBoot+Vue+MySQL的房屋租赁系统

系统展示 系统背景 随着城市化进程的加速和人口流动性的增加&#xff0c;房屋租赁市场逐渐成为城市生活的重要组成部分。然而&#xff0c;传统的房屋租赁方式存在诸多问题&#xff0c;如信息不对称、交易成本高、租赁关系不稳定等&#xff0c;这些问题严重影响了租赁市场的健康…

【MyBatis源码】SqlSession实例创建过程

在MyBatis中&#xff0c;openSession()方法是开启数据库会话的入口&#xff0c;主要作用是生成SqlSession对象。我们从SqlSessionFactory接口入手&#xff0c;其实现类DefaultSqlSessionFactory的openSession()方法用于创建SqlSession实例. SqlSessionFactory接口方法 public…

MoveIt 控制自己的真实机械臂【2】——编写 action server 端代码

完成了 MoveIt 这边 action client 的基本配置&#xff0c;MoveIt 理论上可以将规划好的 trajectory 以 action 的形式发布出来了&#xff0c;浅浅尝试一下&#xff0c;在 terminal 中运行 roslaunch xmate7_moveit_config_new demo.launch 报错提示他在等待 xmate_arm_control…

6977 树的统计

经验值&#xff1a;3200 时间限制&#xff1a;1000毫秒 内存限制&#xff1a;512MB 题目描述 Description 一树上有 nn 个节点&#xff0c;编号分别为 11 到 nn&#xff0c;每个节点都有一个权值 ww。我们将以下面的形式来要求你对这棵树完成一些操作&#xff1a; CHANGE …

SQL之排名RANK()、ROW_NUMBER()、DENSE_RANK() 和 NTILE() 的区别(SQL 和 Hive SQL 都支持)

现有一张student 表,表中包含id、uname、age、score 四个字段,如下所示: 该表的数据如下所示: 一、ROW_NUMBER() 1、概念 ROW_NUMBER() 为结果集中的每一行分配一个唯一的连续整数,编号从 1 开始。‌ 该函数按照指定的顺序进行排序,即使存在相同的值,每一行也会获得…

机器人转人工时,开启实时质检(mod_cti基于FreeSWITCH)

文章目录 前言联系我们实现步骤1. 修改拨号方案2. 启用拨号方案 前言 在客户与机器人对话中&#xff0c;是不能开启质检功能的。因为机器人识别会与质检识别产生冲突。如果用户想通过机器人转接到人工时&#xff0c;开启质检功能&#xff0c;记录客户与人工之间的对话。应该如…

结合Intel RealSense深度相机和OpenCV来实现语义SLAM系统

结合Intel RealSense深度相机和OpenCV来实现语义SLAM系统是一个非常强大的组合。以下是一个详细的步骤指南&#xff0c;帮助你构建这样一个系统。 硬件准备 Intel RealSense深度相机&#xff1a;例如D415、D435或L515。计算平台&#xff1a;一台具有足够计算能力的计算机&…

【JVM 深入了解】JVM 到底包含什么?

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…

炫酷的登录框!(附源码)

大家想看什么前端效果请留言 预览效果 源码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>登录页…

MYSQL-SQL-03-DQL(Data Query Language,数据查询语言)(单表查询)

DQL&#xff08;数据查询语言&#xff09; DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据库中表的记录。 查询关键字: SELECT 在一个正常的业务系统中&#xff0c;查询操作的频次是要远高于增删改的&#xff0c;当我们去访…

从理解路由到实现一套Router(路由)

小伙伴们大家好啊&#xff0c;我是李牌牌。平时在Vue项目中经常用到路由&#xff0c;但是也仅仅处于会用的层面&#xff0c;很多基础知识并不是真正的理解。于是牌牌呢查阅了很多资料&#xff0c;总结下路由相关的知识&#xff0c;查缺不漏&#xff0c;加深自己对路由的理解。 …