【Linux 下】 信号量

article/2025/11/7 3:42:48

文章目录

  • 【Linux 下】 信号量
      • 信号量概念
      • 信号量操作
        • 初始化和销毁
        • P()操作
        • V()操作
        • 理解PV操作
      • 基于信号量与环形队列实现的CS模型
        • 基于信号量和环形队列实现的生产者与消费者模型

【Linux 下】 信号量

信号量概念

信号量(Semaphore)是一种用于实现线程或进程之间同步和互斥的机制。它是由一个计数器和一组相关操作组成。

信号量中的计数器可以表示可用的资源数量或某种状态信息。线程或进程可以通过对信号量进行操作来进行等待或释放资源。

信号量的操作主要有两种:

  1. P(Wait)操作:如果计数器大于0,则将计数器减1;如果计数器为0,则等待,直到计数器大于0才能继续执行。
  2. V(Signal)操作:将计数器加1,并唤醒等待的线程或进程。

简单理解信号量,就可以将信号量理解为一个计数器,记录了当前临界资源的数量多少

简单理解

一个东西的出现,就必然有它出现的道理和用处,信号量可用于解决并发编程中的各种问题,例如资源的互斥访问、线程的同步等。通过合理地使用信号量,可以避免竞态条件死锁等并发编程中常见的问题。

补充:

信号量可以是计数信号量(Counting Semaphore)二进制信号量(Binary Semaphore)

  • 计数信号量:计数信号量可以取任意非负整数值,表示可用的资源数量。线程或进程可以通过 P 操作申请使用资源,通过 V 操作释放资源。当计数信号量的值为0时,表示资源已全部被占用,需要等待其他线程或进程释放资源。
  • 二进制信号量:二进制信号量只能取0或1两个值。常用于实现互斥锁的功能。当二进制信号量的值为1时,表示资源可用,线程或进程可以继续执行。当值为0时,表示资源已被占用,线程或进程需要等待。

下面介绍的是计数信号量


信号量操作

初始化和销毁

sem_init

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5GQmJgFH-1684512300347)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315112821896.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhSOCzL9-1684512300348)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315113337002.png)]

作用:初始化信号量

参数:

  • sem: 指向我们所需要初始化信号量的指针,即指针里面存放的是我们所需要初始化的信号量的地址

  • pshared: 决定该信号量存放的位置,和被线程间分享还是进程间分享

  • **value 😗*信号量的初始值

返回值:

成功返回0,失败返回-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-siYBSut0-1684512300348)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315113651137.png)]

sem_destroy

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bCFw7XFv-1684512300348)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315113751565.png)]

作用:销毁信号量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yf7zacnN-1684512300349)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315114108917.png)]

参数:

  • sem: 所需要销毁的信号量的指针

返回值:

成功返回0,失败返回-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WRE4Nr7K-1684512300349)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315114133245.png)]

P()操作

sem_wait

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zUwWFTp4-1684512300349)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315114246512.png)]

作用:等待信号量,对信号量进行P()操作(–sem),本质是申请使用临界资源[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PcAmmxan-1684512300349)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315114703457.png)]

参数:

  • sem: 所要获取的信号量资源

返回值:

成功返回0,失败返回-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78ngFxTm-1684512300350)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315114931665.png)]

V()操作

sem_post

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KWtQwoVu-1684512300350)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315115042139.png)]

作用:对信号量进行V()操作(++sem)本质是释放临界资源[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Gw6AvFH-1684512300350)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315115155306.png)]

参数:

  • sem: 所要获取的信号量资源

返回值

成功返回0,失败返回-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOC7HwJe-1684512300351)(C:\Users\LANSHUHANG\AppData\Roaming\Typora\typora-user-images\image-20230315115246400.png)]

理解PV操作

实际上p(),V()操作就是对信号量进行–,++操作,本质就是通过p()操作等待或者申请使用的临界资源,通过V()操作,将获得的临界资源归还或是释放;

从上面的理解我们不难得知,信号量也是临界资源,,而我们在前面的线程互斥曾说过,++,–并不是原子性操作,所以说sem的P(),V()操作实际上是极不安全的,这就说明对信号量的++,–操作是存在线程安全问题的;所以我们对信号量的操作是需要互斥锁


基于信号量与环形队列实现的CS模型

补充概念

**并行(Parallel)串行(Serial)**是描述多任务执行方式的概念。

串行指的是按顺序一个接一个地执行任务或指令。在串行执行中,每个任务或指令必须在前一个任务或指令完成之后才能开始执行。这意味着任务是按照线性顺序进行处理的,没有同时执行多个任务的能力。串行执行适用于那些互相依赖的任务,其中一个任务的结果需要作为输入传递给下一个任务。

并行是指同时执行多个任务或指令。在并行执行中,多个任务可以在同一时间段内同时进行,彼此之间相互独立。并行执行可以通过同时利用多个处理器核心、多线程或分布式计算等技术实现。并行执行可以大大提高任务的执行速度和系统的吞吐量,尤其适用于那些可以被分解成独立子任务的问题。

并行和串行之间存在一定的权衡和适用场景。串行执行简单直观,适用于顺序执行的任务,但可能导致执行时间较长。而并行执行可以提高任务的执行效率,但可能需要额外的并行处理能力和复杂的同步机制来确保正确性。

在现代计算机系统中,通常会同时应用并行和串行的概念。例如,一个程序可以使用串行方式执行某些任务,而使用并行方式执行某些可以并行处理的子任务。通过合理地组织和分配任务,可以充分利用系统资源,提高计算性能和效率。

并发(Concurrency)

**并发(Concurrency)**是指系统能够同时处理多个独立的任务、操作或事件的能力。并发的关键在于任务之间的重叠执行,不一定需要同时进行,但可以交替执行以提高效率和资源利用率。

并发可以在单个处理器上通过时间分片或任务切换实现,也可以利用多个处理器核心、多线程或分布式系统来实现。

并发编程涉及多个执行流(线程、进程或任务)同时执行,这些执行流可以独立运行并相互交互。并发编程的目标是保证多个执行流之间的正确同步和协调,避免竞态条件、死锁、饥饿等并发问题。

基于信号量和环形队列实现的生产者与消费者模型

合理的运用信号量可以实现线程并发操作

实现思路

  • 使用环形队列存储数据(逻辑上的数据:空位置和数据。配合指针来实现这个逻辑),充当“超市”,

    • 控制环形队列的精髓

      index %= _cap;
      
    • 指针:p_step– 代表生产者当前所处的坐标,通常指向的是空位置资源处;c_step–代表消费者当前所处的坐标,通常指向的是数据资源处

  • 通过互斥量和信号量维持生产者和消费者之间的关系

    • 消费者关注的是环形队列中的产品资源,只要有数据资源,就进行消费,没有数据资源,就停下里等待数据资源
    • 生产者关注的是环形对列中的空位置资源,只要有空位置,就进行“生产”,没有空位置,就停下等待空位置资源
    • 使用俩个信号量描述空位置资源和数据资源的状态(empty_sem,data_sem)
  • 规定环形队列大小为10,可以自行调节

  • 同步实现精髓:

    • p_step,c_step一开始都指向下标为0,代表生产者和消费同时出发,但得遵循以下规则
      • 消费者永远都是在追随生产者的步伐–
      • 生产者不能将消费者套圈–
    • 初始empty_sem为10,data_sem为0;

理解图

一些说明:

  • 因为生产者和消费者所关注的是不同的临界资源,所以使用俩把互斥锁,对不同的临界资源加锁,逻辑上更加合理,且效率更高
  • 再理解:多生产者和多消费者模型的优势实际上在于可以并行处理的和生产数据
    • 生产实际上分为俩步:1.生产数据 (通常是耗时的)2.分布数据(将数据添加到环形队列中)
    • 消费也是分为俩步:1.取出数据 2.处理数据(耗时)
    • 多个线程都能申请到临界资源(空位置资源或数据资源),而后就可以同时对数据处理;这是条件变量实现的cs模型所不能比拟的

主逻辑代码

#include <iostream>
#include "Ringqueue.hpp"
#include <unistd.h>
#include <time.h>
using namespace Lsh_ring_queue;void* Produce(void* args)
{auto rq =(Ring_queue<int>* )args;while(1){//生产:1. 生产数据 2.将数据添加到环形队列中int data=rand()%20+1;std::cout<<"生产者->"<<pthread_self()<<"生产了: "<<data<<std::endl;rq->Push(data);sleep(1);}
}
void* Comsumer(void * args)
{auto rq=(Ring_queue<int>*) args;while(1){//消费: 1.从环形队列中取出数据 2.处理数据--此处只是进行了数据打印,实际中可以将该部分换成一些业务逻辑int data;rq->Pop(&data);std::cout<<"消费者->"<<pthread_self()<<"消费了: "<<data<<std::endl;sleep(1);}
}int main()
{srand((unsigned int)time(nullptr));pthread_t p;pthread_t p1;pthread_t p2;pthread_t c;pthread_t c1;pthread_t c2;Ring_queue<int> * rq=new Ring_queue<int>();pthread_create(&p,nullptr,Produce,(void*)rq);pthread_create(&p1,nullptr,Produce,(void*)rq);pthread_create(&p2,nullptr,Produce,(void*)rq);pthread_create(&c,nullptr,Comsumer,(void*)rq);pthread_create(&c1,nullptr,Comsumer,(void*)rq);pthread_create(&c2,nullptr,Comsumer,(void*)rq);pthread_join(p,nullptr);pthread_join(c,nullptr);return 0;
}

环形队列实现代码:

#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include <semaphore.h>namespace Lsh_ring_queue
{const int de_cap = 10;template <class T>class Ring_queue{private:int _cap;std::vector<T> _rq;sem_t _blank_sem; // 生产者所关心的信号量  初始值为10 代表10个空格 初始值为10sem_t _data_sem;  // 消费者所关系的信号量  初始值为0  代表0个数据  初始值为0int p_step; // 生产者和消费者所在的位置int c_step;pthread_mutex_t p_mtx;pthread_mutex_t c_mtx;public:Ring_queue():_cap(de_cap) ,_rq(de_cap) ,p_step(0),c_step(0){//第二个参数未0,代表在线程间共享该信号量sem_init(&_blank_sem,0,10);sem_init(&_data_sem,0,0);pthread_mutex_init(&p_mtx,nullptr);pthread_mutex_init(&c_mtx,nullptr);}void Push(T& in){//对空位置进行减减操作sem_wait(&_blank_sem);pthread_mutex_lock(&p_mtx);_rq[p_step]=in;p_step++;p_step%=_cap; //更新生产者的位置pthread_mutex_unlock(&c_mtx);sem_post(&_data_sem);}void Pop(T* out){sem_wait(&_data_sem);pthread_mutex_lock(&c_mtx);*out=_rq[c_step];c_step++;c_step%=_cap;pthread_mutex_unlock(&c_mtx);sem_post(&_blank_sem);}~Ring_queue(){sem_destroy(&_blank_sem); sem_destroy(&_data_sem); pthread_mutex_destroy(&p_mtx); pthread_mutex_destroy(&c_mtx); }};
}

运行结果:

     pthread_mutex_unlock(&c_mtx);sem_post(&_blank_sem);}~Ring_queue(){sem_destroy(&_blank_sem); sem_destroy(&_data_sem); pthread_mutex_destroy(&p_mtx); pthread_mutex_destroy(&c_mtx); }
};

}


**运行结果:**![](https://img-blog.csdnimg.cn/img_convert/f99068201396b3ae7cb89b7577e41065.png)

http://chatgpt.dhexx.cn/article/HJbOjd9k.shtml

相关文章

Linux 信号量

信号量 信号量信号量的定义信号量理论例子Linux信号量机制使用信号量 信号量 信号量:用于管理对资源的访问。 &#xff08;1&#xff09; 当我们编写的程序使用了线程时&#xff0c;不管它是运行在多用户系统上、多进程系统上,还是运行在多用户多进程系统上&#xff0c;我们通…

Linux内核信号量:二值信号量/互斥信号量,计数信号量,读写信号量

《semaphore信号量&#xff1a;一个简单的示例程序》用户态程序 目录 概念 应用场景 使用方法 内核信号量的构成 信号量的API 初始化 PV操作 获取信号量&#xff08;P&#xff09; 释放内核信号量&#xff08;V&#xff09; 补充 内核信号量的使用例程 场景1 场景…

Linux系统中信号量的基本使用方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用信号量的方法。 目录 第一&#xff1a; 父子进程相隔1s报数一次 第二&#xff1a;利用信号量实现父子进程通信 信号量(Semaphore)&#xff0c;有时被称为信号灯&#xff0c;是在多线程环境下使用的一种设施&#…

信号量【Linux】

文章目录 1. POSIX信号量1.1 引入1.2 概念1.3 PV原语&#xff08;原理&#xff09;1.4 相关接口 2. 二进制信号量3. 基于环形队列的生产消费模式3.1 介绍3.2 为什么要使用环形队列3.3 环形队列的作用3.4 实现互斥和同步两个信号量框架生产和消费的逻辑完善环形队列1信号量完善环…

Linux信号量操作

信号量简介&#xff1a; 在对于临界区资源管理的过程中&#xff0c;多个程序同时访问一个共享资源经常容易引发一系列问题&#xff1a;如死锁&#xff0c;结果不唯一等等&#xff0c;在1965年&#xff0c;由荷兰科学家E.W.Dijkstra提出了一种新的进程同步工具&#xff0c;信号…

【关于Linux中----信号量及其使用场景】

文章目录 一、解释信号量1.1 概念的引入1.2 信号量操作和使用接口 二、信号量使用场景2.1 引入环形队列&&生产消费问题2.2 代码实现2.3 对于多生产多消费的情况2.4 申请信号量和加锁的顺序问题2.5 多生产多消费的意义 一、解释信号量 1.1 概念的引入 我们知道&#x…

linux(信号量)

信号量 几个基本概念临界资源临界区原子性互斥 信号量后台进程前台进程 信号储存信号处理信号(信号捕捉) 发送信号1、键盘产生&#xff1a;2、系统调用接口发送信号3、由软件条件产生信号4、硬件异常发送信号 内核中的信号量**信号量在内核中的数据结构****信号集操作函数** 信…

Linux--信号量

1.信号量的定义: 信号量是一个特殊的变量&#xff0c;一般取正数值。它的值代表允许访问的资源数目&#xff0c; 获取资源时&#xff0c;需要对信号量的值进行原子减一&#xff0c;该操作被称为p操作。当信号量值为0时&#xff0c;代表没有资源可用&#xff0c;p操作会阻塞。释…

【Linux】Linux的信号量集

所谓信号量集&#xff0c;就是由多个信号量组成的一个数组。作为一个整体&#xff0c;信号量集中的所有信号量使用同一个等待队列。Linux的信号量集为进程请求多个资源创造了条件。Linux规定&#xff0c;当进程的一个操作需要多个共享资源时&#xff0c;如果只成功获得了其中的…

linux信号量简介

一、什么是信号量 为了防止多个程序同时访问一个共享资源而引发的一系列问题&#xff0c;我们需要一种访问机制&#xff0c;它可以通过生成并使用令牌来授权&#xff0c;在同一时刻只能有一个线程访问代码的临界区域。 临界区域是指执行数据更新的代码需要独占式地执行。而信…

Linux下信号量使用总结

目录 1.Linux下信号量简介 2.POSIX信号量 2.1 无名信号量 2.2 有名信号量 3.System V信号量 1.Linux下信号量简介 信号量是解决进程之间的同步与互斥的IPC机制&#xff0c;互斥与同步关系存在的症结在于临界资源。 临界资源是在同一个时刻只容许有限个&#xff08;一般只有…

Linux信号量详解

Linux信号量详解 1.什么是信号量信号量是一种特殊的变量&#xff0c;访问具有原子性。只允许对它进行两个操作&#xff1a;1)等待信号量当信号量值为0时&#xff0c;程序等待&#xff1b;当信号量值大于0时&#xff0c;信号量减1&#xff0c;程序继续运行。2)发送信号量将信号量…

Linux进程间通信—信号量

一、概述 进程间通信&#xff08;interprocess communication&#xff0c;简称 IPC&#xff09;指两个进程之间的通信。系统中的每一个进程都有各自的地址空间&#xff0c;并且相互独立、隔离&#xff0c;每个进程都处于自己的地址空间中。所以同一个进程的不同模块譬如不同的函…

Linux操作系统-信号量

信号量也属于一种进程间通信的机制&#xff0c;与其他的进程间通信不同&#xff0c;信号量不是用来传输数据的&#xff0c;而是用来进程间同步与互斥。除此之外&#xff0c;信号量还可以实现线程间的互斥。 信号量是什么&#xff1f; 信号量的本质是一个计数器。 一个信号量…

Linux·信号量全解

目录 信号量 进程间 【无名信号量完成 有血缘关系的进程间 互斥】 知识点2【有名信号量 没有血缘进程互斥】 1、创建一个有名信号量 2、信号量的关闭&#xff1a; 3、信号量文件的删除 4、P操作 sem_wait V操作sem_post 销毁信号量sem_destroy 知识点3【有名信号量 没…

Linux-----信号量

信号量 信号量原理信号量概念信号量函数基于环形队列的生产消费模型空间和数据资源生产者和消费者申请、释放信号量模拟实现基于环形队列的生产者消费者模型 信号量原理 之前我们知道被多个执行流同时访问的公共资源叫做临界资源&#xff0c;而临界资源不保护的话会造成数据不…

Linux信号量

文章目录 POSIX信号量信号量的原理信号量的概念信号量函数 二元信号量模拟实现互斥功能基于环形队列的生产消费模型空间资源和数据资源生产者和消费者申请和释放资源必须遵守的两个规则代码实现信号量保护环形队列的原理 POSIX信号量 信号量的原理 我们将可能会被多个执行流同…

Linux —— 信号量

目录 一、POSIX信号量 1. 什么是信号量 2. 信号量的基本原理 二、与信号量相关的操作 1. 初始化信号量 2. 销毁信号量 3. 等待信号量 4. 发布信号量 三、基于环形队列的生产者消费者模型 1. 空间资源和数据资源 2. 生产者和消费者申请和释放资源 四、模拟实现基于…

Double取值intValue()与doubleValue()之参数缺省

Double调用intValue()是四舍五入向下取整。 调用doubleValue()才是取double真实值。

java.lang.NullPointerException: Attempt to invoke virtual method ‘int java.lang.Integer.intValue()‘

问题 对于PreparedStatement 对象设置参数时&#xff0c; 提示该错误; java.lang.NullPointerException: Attempt to invoke virtual method ‘int java.lang.Integer.intValue()’ 具体问题 2022-09-06 21:28:10.695 11368-11755/com.example.electronicmall E/AndroidRunt…