信号量详细解说

2023-11-09

1、信号量概述 

进化版的互斥锁(1 --> N)

由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。

信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发。

2、主要应用函数: 

sem_init() 函数              功能:初始化一个信号量

sem_wait()函数              功能:给信号量加锁 --

sem_trywait() 函数        功能:尝试对信号量加锁 --

sem_timedwait() 函数   功能:限时尝试对信号量加锁 --

sem_post() 函数            功能:给信号量解锁 ++

sem_destroy() 函数       功能:销毁一个信号量

以上6 个函数的返回值都是:成功返回0, 失败返回-1,同时设置errno。(注意,它们没有pthread前缀)

sem_t类型,本质仍是结构体。但应用期间可简单看作为整数,忽略实现细节(类似于使用文件描述符)。

sem_t   sem; 规定信号量sem不能 < 0头文件 <semaphore.h>

3、函数分析   

<1>、初始化一个信号量 

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

参1:sem信号量

参2:pshared取0用于线程间取非0(一般为1)用于进程间

参3:value指定信号量初值

<2>、给信号量加锁 -- 

int sem_wait(sem_t *sem); 

<3>、给信号量解锁 ++ 

 int sem_post(sem_t *sem);  

<4>、尝试对信号量加锁 --    (与sem_wait的区别类比lock和trylock)

 int sem_trywait(sem_t *sem);  

 <5>、限时尝试对信号量加锁 --

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 

参2:abs_timeout采用的是绝对时间。

定时1秒:

time_t cur = time(NULL); 获取当前时间。

struct timespec t; 定义timespec 结构体变量t

t.tv_sec = cur+1; 定时1秒

t.tv_nsec = t.tv_sec +100;

sem_timedwait(&sem, &t); 传参

 <6>、销毁一个信号量

int sem_destroy(sem_t *sem); 

4、信号量基本操作:

sem_wait: 1. 信号量大于0,则信号量-- (类比pthread_mutex_lock)

  | 2. 信号量等于0,造成线程阻塞

对应

  |

sem_post: 将信号量++,同时唤醒阻塞在信号量上的线程 (类比pthread_mutex_unlock)

但,由于sem_t的实现对用户隐藏,所以所谓的++、--操作只能通过函数来实现,而不能直接++、--符号。

信号量的初值,决定了占用信号量的线程的个数。

5、信号量示例 

生产者消费者条件变量模型

       线程同步典型的案例即为生产者消费者模型,而借助条件变量来实现这一模型,是比较常见的一种方法。假定有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程同时操作一个共享资源(一般称之为汇聚),生产向其中添加产品,消费者从中消费掉产品。

/*信号量实现 生产者 消费者问题*/
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>

#define NUM 5               

int queue[NUM];                                     //全局数组实现环形队列
sem_t blank_number, product_number;                 //空格子信号量, 产品信号量

void *producer(void *arg)
{
    int i = 0;

    while (1) {
        sem_wait(&blank_number);                    //生产者将空格子数--,为0则阻塞等待
        queue[i] = rand() % 1000 + 1;               //生产一个产品
        printf("----Produce---%d\n", queue[i]);        
        sem_post(&product_number);                  //将产品数++

        i = (i+1) % NUM;                            //借助下标实现环形
        sleep(rand()%3);
    }
}

void *consumer(void *arg)
{
    int i = 0;

    while (1) {
        sem_wait(&product_number);                  //消费者将产品数--,为0则阻塞等待
        printf("-Consume---%d\n", queue[i]);
        queue[i] = 0;                               //消费一个产品 
        sem_post(&blank_number);                    //消费掉以后,将空格子数++

        i = (i+1) % NUM;                            //借助下标实现环形
        sleep(rand()%3);
    }
}

int main(int argc, char *argv[])
{
    pthread_t pid, cid;

    sem_init(&blank_number, 0, NUM);                //初始化空格子信号量为5
    sem_init(&product_number, 0, 0);                //产品数为0

    pthread_create(&pid, NULL, producer, NULL);
    pthread_create(&cid, NULL, consumer, NULL);

    pthread_join(pid, NULL);
    pthread_join(cid, NULL);

    sem_destroy(&blank_number);
    sem_destroy(&product_number);

    return 0;
}

 6、结果分析

 

百度云盘:链接:https://pan.baidu.com/s/11b634VvKMIsGdahyBLpZ3Q   提取码:6666

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

信号量详细解说 的相关文章

随机推荐

  • valgrind简介与使用

    一 valgrind简介 Valgrind是一款用于内存调试 内存泄漏检测以及性能分析 检测线程错误的软件开发工具 Valgrind 是运行在Linux 上的多用途代码剖析和内存调试软件 主要包括Memcheck Callgrind Cac
  • Mysql API实践

    Mysql API实践 MySql 5 6的API官方见 http dev mysql com doc refman 5 6 en c api function overview html 下面给出一个简单的例子 include
  • Mybatis快速入门

    基本步骤 1 2 导入坐标 使用maven来构建项目只需将所需依赖注入
  • 【Java】基础知识练习题(编程题为主!)

    答案后续发布 欢迎来到小明的练习空间 一 异常 编程题 1 1 题目一 1 2 题目二 1 3 题目三 1 4题目四 二 集合 问答 编程题目 2 1 集合 编程题 Collection接口 2 2 集合 编程题 Collection接口
  • 调用用于获取服务器信息,一种获取测试用例的方法以及服务器

    1 一种获取测试用例的方法 其特征在于 包括 获取被测对象的函数调用关系信息 获取目标函数 所述目标函数为根据所述被测对象的被测版本源码和历史版本源码的差异信息确定的相关函数 所述被测版本源码是所述历史版本源码经过处理得到的 根据所述函数调
  • openEuler怎么查询端口是否被占用-ChatGPT回答

    openEuler怎么查询端口是否被占用 ChatGPT回答 在 openEuler 系统中 你可以使用以下命令来查询端口是否被占用 查看所有使用中的端口 lsof i 查看指定端口是否被占用 lsof i 端口号 例如 查看 80 端口是
  • 高次谐波电压、电流主要有哪些危害?

    高次谐波电压 电流主要有哪些危害 答 高次谐波电流超过一定限度会引起发电机 变压器 电动机损失增大 产生过热 高次谐波电压可能引起设备异常振动 继电保护误动 计量误差增大 晶闸管装置失控和影响通信质量等 高次谐波电流 电压更容易使电力电容器
  • JS获取随机或指定数据

    1 不能全是相同的数字或者字母 如 000000 111111 222222 333333等等 2 不能是连续数字 如 123456 12345678 87654321等等 顺序表 static String orderStr static
  • 模板类的继承问题

    首先大家来看这段代码 plain view plain copy class A public void Show cout lt lt A Show lt lt endl void Fun cout lt lt A Fun lt lt e
  • [CVPR2020] DoveNet: Deep Image Harmonization via Domain Verification 论文解读

    论文地址和代码 数据库和代码已公布 https github com bcmi Image Harmonization Datasets 论文地址 https arxiv org abs 1911 13239 一 简介 图像合成 image
  • python selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id

    标题问题的解决办法参考了这篇文章 然后成功了 1条消息 关于新版本selenium定位元素报错 WebDriver object has no attribute find element by id 等问题 selenium新版本定位 热
  • ADC各参数含义

    文章目录 前言 一 ADC工作原理 二 详细参数 1 分辨率 2 转换率 采样率 转化时间 3 最低有效位 LSB 最高有效位 MSB 4 量化误差 5 SNR 6 失调误差 7 增益误差 8 微分非线性 DNL 9 积分非线性 INL 1
  • 《数据分析思维》:分析方法与业务知识

    小飞象 读书会 生活从来不会刻意亏欠谁 它给你一块阴影 必会在不远处撒下阳光 读书交流 3期 数据分析方法与业务知识 data analysis 分享人 木兮 欢迎大家参加这次读书会的直播分享 本次分享由学委木兮来带大家梳理一下 数据分析思
  • 【STM32篇】步进电机之S型曲线

    使用步进电机的S曲线算法的目的是为了使电机缓慢加速到目标转速或从高转速减速到0 防止电机在高转速时立即停止而对电机造成损伤 减少电机的使用寿命 本文主要讲述S型算法的使用 对于具体的原理 可通过其他博主的文章学习 图1 S算法加减速图 如图
  • libvirt笔记 PCI设备直通

    PCI设备直通功能允许将主机上的物理PCI设备直接分配给来宾机 客户操作系统驱动程序可以直接使用设备硬件 而无需依赖主机操作系统的任何驱动程序功能 在使用PCI设备直通时需要注意一些事项 当将PCI设备直接分配给客户机时 如果不首先从客户机
  • 静态代码和动态代码的区别_动态改变的代码设计思想

    前言 我看过很多书 知道那些作者在推广什么 相对书里的东西落地 还是一个不容易的过程 我看过很多行业的代码 持续多年的积累 聊过一些老板 对代码改造的看法 为什么 程序员这么难 我将用4个方向 来解释代码设计中的设计思路和方法 给大家展现一
  • Android登录 之 GooglePlay登录

    想法 写了好久代码了 但是都没有具体的总结下 总是用到的时候 再去翻看资料 一看就是一堆 到最后都不一定能管用 近期做了一些项目 涉及到了登录授权 细回想下 自己接过的登录授权还真心不少 不同的授权都会一一列举 以后方便自己 也希望能够方便
  • Fatal error: Cannot declare class ***, because the name is already in use in D:\www\test.php

    报错信息 Fatal error Cannot declare class because the name is already in use in D www test php on line 5 报错原因 该class 文件在其他引入
  • Tomcat控制台打印输出中文时的乱码问题

    这个问题我参考了许多网上的解决方法 这个方法是比较迅速与方便的 产生这个问题的原因是Windows默认编码集为GBK 由于使用startup bat启动Tomcat时 它会读取catalina bat的代码并打开一个新窗口运行 打开的cmd
  • 信号量详细解说

    1 信号量概述 进化版的互斥锁 1 gt N 由于互斥锁的粒度比较大 如果我们希望在多个线程间对某一对象的部分数据进行共享 使用互斥锁是没有办法实现的 只能将整个数据对象锁住 这样虽然达到了多线程操作共享数据时保证数据正确性的目的 却无形中