Linux线程之信号量(semaphore)

2023-09-19 09:41:25

1. 头文件

#include<semaphore.h>

2. 类型

2.1. 类型值

//信号量类型
sem_t   semTest;

3. 接口

3.1. 信号量接口

3.1.1 动态初始化资源

/*
 * 函数名称:sem_init
 * 功能:动态初始化信号量资源
 * 参数:
 * 		__sem: 指向待初始化的信号量对象地址
 * 		__pshared:0表示信号量是在同一个进程中的不同线程间进行同步,非0表示信号量共享在不同的进程中。
 * 		__value:表示初始化可共享的线程的数量
 * 返回值:0--成功,-1-失败,并会把errno设置为具体的错误类型
*/
int sem_init (sem_t *__sem, int __pshared, unsigned int __value);

3.1.2. 动态释放资源

/*
 * 函数名称:sem_destroy
 * 功能:动态释放信号量资源
 * 参数:
 * 		__sem: 指向需要释放的信号量对象地址
 * 返回值:0--成功,-1--失败,并会把errno设置为具体的错误类型
*/
int sem_destroy (sem_t *__sem);

3.1.3. 信号量锁定

/*
 * 函数名称:sem_wait
 * 功能:当信号量的值大于0时则减1直接返回,当信号量的值小于等于0则阻塞当前线程直到信号量的值大于0时,执行减1后返回
 * 参数:
 * 		__sem: 指向需要等待的信号量对象地址
 * 返回值:0--成功,-1--失败,并会把errno设置为具体的错误类型
*/
int sem_wait (sem_t *__sem);

3.1.4. 带超时时间的信号量锁定

//时间结构体
struct timespec
{
	__time_t tv_sec;   //秒
	long int tv_nsec;	//纳秒
};
/*
 * 函数名称:sem_timewait
 * 功能:当信号量的值大于0时则减1直接返回,当信号量的值小于等于0则阻塞当前线程直到达到指定的超时时间后返回,或者为达到超时时间信号量的值大于0时,执行减1后返回
 * 参数:
 * 		__sem: 指向需要等待的信号量对象地址
 * 		__abstime:设置的相对于UTC时间的绝对超时时间,需要先获取当前时间然后在加上超时时间
 * 返回值:0--成功,-1--失败,并会把errno设置为具体的错误类型
*/
int sem_timedwait (sem_t *__sem, const struct timespec *__abstime); 

3.1.5. 不阻塞信号量锁定

/*
 * 函数名称:sem_trywait
 * 功能:测试信号量是否可以减1,如果不能则直接返回,并返回错误码
 * 参数:
 * 		__sem: 指向需要减1的信号量对象地址
 * 返回值:0--成功,-1--失败,并会把errno设置为具体的错误类型
*/
int sem_trywait (sem_t *__sem);

3.1.6. 信号量解锁

/*
 * 函数名称:sem_post
 * 功能:对信号量进行加1操作,即解锁
 * 参数:
 * 		__sem: 指向信号量对象地址
 * 返回值:0--成功,-1--失败,并会把errno设置为具体的错误类型
*/
int sem_post (sem_t *__sem);

3.1.6. 获取当前信号量的值

/*
 * 函数名称:sem_getvalue
 * 功能:获取当前信号量的值
 * 参数:
 * 		__sem: 指向信号量对象地址
 * 		__sval:指向当前信号量值的存储地址
 * 返回值:0--成功,-1--失败,并会把errno设置为具体的错误类型
*/
int sem_getvalue (sem_t * __sem, int * __sval);

4. 示例

4.1. 信号量示例

##include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

//全局信号量定义
sem_t g_sem;

static void* semWaitThread(void *arg)
{
    std::cout << "enter semWaitThread " << pthread_self() << " ." << std::endl;
    
    sem_wait(&g_sem);
    
    //获取当前信号量值
    int iValue = 0;
    sem_getvalue(&g_sem, &iValue);
    std::cout << "thread id is " << pthread_self() << ", sem value is " << iValue << std::endl;
    std::cout << "semWaitThread continue " << pthread_self() << " ." << std::endl;

    return nullptr;
}

static void* semPostThread(void *arg)
{
    std::cout << "enter semPostThread " << pthread_self() << " ." << std::endl;
    
    sem_post(&g_sem);
    
    //获取当前信号量值
    int iValue = 0;
    sem_getvalue(&g_sem, &iValue);
    std::cout << "thread id is " << pthread_self() << ", sem value is " << iValue << std::endl;
    std::cout << "semPostThread continue " << pthread_self() << " ." << std::endl;
    return nullptr;
}

int main()
{
    //信号量初始化
    sem_init(&g_sem, 0, 2);

    //创建3个信号量阻塞线程
    pthread_t semWaitThreadId[3];
    for (int i = 0; i < 3; i++)
    {
        int iValue = i+1;
        pthread_create(&semWaitThreadId[i], nullptr, semWaitThread, nullptr);
        pthread_detach(semWaitThreadId[i]);
        sleep(1);
    }
    
    sleep(3);
    //创建3个信号量释放线程
    pthread_t semPostThreadId[3];
    for (int i = 0; i < 3; i++)
    {
        int iValue = i+1;
        pthread_create(&semPostThreadId[i], nullptr, semPostThread, nullptr);
        pthread_detach(semPostThreadId[i]);
        sleep(1);
    }

    //信号量销毁
    sem_destroy(&g_sem);

    return 0;
}
enter semWaitThread 140258284926528 .
thread id is 140258284926528, sem value is 1
semWaitThread continue 140258284926528 .
enter semWaitThread 140258284926528 .
thread id is 140258284926528, sem value is 0
semWaitThread continue 140258284926528 .
enter semWaitThread 140258284926528 . 因为信号量为2所以第三个线程会在此处阻塞。
enter semPostThread 140258276533824 . 此处有一个post操作信号量加1,后续被阻塞的线程获取信号量继续执行。
thread id is 140258276533824, sem value is 1 此时被阻塞的线程继续执行
semPostThread continue 140258276533824 .
thread id is 140258284926528, sem value is 0
semWaitThread continue 140258284926528 .
enter semPostThread 140258284926528 .
thread id is 140258284926528, sem value is 1
semPostThread continue 140258284926528 .
enter semPostThread 140258284926528 .
thread id is 140258284926528, sem value is 2
semPostThread continue 140258284926528 .
更多推荐

udp的简单整理

最近思考udp处理的一些细节,根据公开课,反复思考,终于有所理解,做整理备用。0:简单汇总1:udp是基于报文传输的,接收方收取数据时要一次性读完。2:借助udp进行发包,发大包也是没有问题的,借助IP层ip分片。===》ip分片可以发生在原始主机上,也可以发生在中间路由器上(MTU值)===》ip分片后,可以再分片,

Swift 5.5之Continuation

Continuation是Swift5.5中引入的一种新的编程模型,用于管理异步任务的结果。它允许您在异步任务完成后使用结果继续执行代码,可以与Async/Await一起使用,以简化异步编程。下面是使用Continuation的基本步骤:导入Continuation模块在使用Continuation之前,需要在代码文件

mysql知识大全

MySQL知识大全(2)MySqL基础为1—7(增删改查基础语法),MySQL进阶知识为8—11(约束、数据库设计、多表查询、事务)1、数据库相关概念以前我们做系统,数据持久化的存储采用的是文件存储。存储到文件中可以达到系统关闭数据不会丢失的效果,当然文件存储也有它的弊端。假设在文件中存储以下的数据:姓名年龄性别住址张

Python案例实现|租房网站数据表的处理与分析

在综合实战项目中,“北京链家网”租房数据的抓取任务已在上一篇完成,得到了数据表bj_lianJia.csv,如图1所示。该数据表包含ID、城区名(district)、街道名(street)、小区名(community)、楼层信息(floor)、有无电梯(lift)、面积(area)、房屋朝向(toward)、户型(mo

leetcode 10. 正则表达式匹配

2023.9.20感觉是目前做过dp题里最难的一题了...本题首要的就是需要理解题意,翻了评论区我才发现之前一直理解的题意是错的。我原来理解的“*匹配0次”是指:*直接消失,不会影响到前面的字符。但是*和前一个字符其实是连体的,所以说:*如果匹配0次,那么前一个字符就没了,消失了;*如果匹配1次,那么才相当于*消失了,

【Python】PySpark 数据处理 ① ( PySpark 简介 | Apache Spark 简介 | Spark 的 Python 语言版本 PySpark | Python 语言场景 )

文章目录一、PySpark简介1、ApacheSpark简介2、Spark的Python语言版本PySpark3、PySpark应用场景4、Python语言使用场景一、PySpark简介1、ApacheSpark简介Spark是Apache软件基金会顶级项目,是开源的分布式大数据处理框架,专门用于大规模数据处理,是一款

Windows11系统C盘用户文件夹下用户文件夹为中文,解决方案

说明:1.博主电脑为Windows11操作系统,亲测有效,修改后无任何影响,软件都可以正常运行!2.Windows10系统还不知道可不可行,因为Windows11的计算机管理中没有本地用户和组,博主在csdn上看到很多博主有发Windows10的解决方案,有通过“注册表”的,也有通过“本地用户和组”的,大家可以自己去小

OpenCV实现“蓝线挑战“特效

原理算法原理可以分为三个流程:1、将视频(图像)从(顶->底)或(左->右)逐行(列)扫描图像。2、将扫描完成的行(列)像素重新生成定格图像。3、使用原帧图像像素填充未扫描到的像素。图像扫描首先第一步,拿到一个视频(很多帧图像)可以简单的看成图像处理。我们需要将图像从顶到底逐行进行像素扫描,当然也可以从左到右逐列扫描,

在服务器上创建git仓库

1、在服务器上创建git仓库选择一个创建文件夹的地方,这个地方不会将源码存放在这里,只用于版本控制#创建一个专门放置git的文件夹,也可以叫其它名mkdirgit&&cdgit#创建自己项目的文件夹,文件夹后面要带.gitmkdirmy_object.git&&cdmy_object.git#初始化gitinit--b

Vue3中如何通过内嵌iframe传递参数与接收参数

前言Vue3是一种用于构建用户界面的JavaScript框架,它提供了很多方便的功能和工具来开发交互式的Web应用程序。其中一个常见的需求是在Vue应用程序中内嵌一个iframe,并且需要在两者之间传递参数。本文将介绍如何在Vue3中实现此功能,包括如何在Vue组件中内嵌iframe以及如何传递参数和接收参数。内嵌if

虹科产品 | HK-ATTO 光纤通道卡利用FC-NVMe 提升全闪存存储阵列性能

一、虹科ATTO光纤通道HBA随着对高速数据访问和低延迟存储解决方案的需求日益增长,虹科ATTO最新的光纤通道创新技术带来了改变游戏规则的突破。原生光纤通道和第二代FC-NVMe标准使虹科ATTO光纤通道HBA能够提供无与伦比的速度和效率,显著加快全球数据中心的全闪存阵列性能。原生光纤通道支持可确保数据密集型共享工作负

热文推荐