Linux下信号量使用总结

news2024/11/28 2:54:55

目录

1.Linux下信号量简介

2.POSIX信号量

2.1 无名信号量

2.2 有名信号量

3.System V信号量


1.Linux下信号量简介

       信号量是解决进程之间的同步与互斥的IPC机制,互斥与同步关系存在的症结在于临界资源。
临界资源是在同一个时刻只容许有限个(一般只有一个)进程可以访问(读)或更改(写)的资源,
临界资源包括:硬件资源(处理器、内存、存储器以及其他外围设备等)和软件资源(共享代码段、共享结构和变量等)。
信号量是描述某一种资源是否可用的变量,信号量的值表示当前可用的资源的数目linux查看信号量命令,若信号量的值等于0则意味着目前没有可用的资源。
对信号量进行的两个原子操作(PV操作)
P操作:等待。假如sv小于0,减少sv。假如sv为0,挂起这个进程的执行。
V操作:发送信号。假如有进程被挂起等待sv,使其恢复执行。假如没有进行被挂起等待sv,降低sv。

Linux系统承继了Unix系统的两种信号量:
(1)内核信号量,由内核控制路径使用
(2)用户态进程使用的信号量,分为POSIX信号量和System V信号量。
(3)POSIX信号量又分为有名信号量和无名信号量,有名信号量,其值保存在文件中,可用于线程、进程间的同步;无名信号量linux deepin,其值保存在显存中。

POSIX信号量与System V信号量的区别如下:
(1)POSIX信号量是个非负整数,常用于线程间同步。System V信号量是一个或多个信号量的集合,是一个信号量结构体,信号量是它的一部份,常用于进程间同步。
(2)POSIX信号量的引用头文件是,而System V信号量的引用头文件是。
(3)System V信号量是复杂的,而POSIX信号量是简单的。


2.POSIX信号量

头文件
/usr/include/semaphore.h
API
(1)int sem_init (sem_t *__sem, int __pshared, unsigned int __value);
(2)int sem_destroy (sem_t *__sem);
(3)sem_t *sem_open (const char *__name, int __oflag, ...);
(4)int sem_close (sem_t *__sem);
(5)int sem_unlink (const char *__name);
(6)int sem_wait (sem_t *__sem);
(7)int sem_timedwait (sem_t *__restrict __sem,
              const struct timespec *__restrict __abstime);
(8)int sem_trywait (sem_t *__sem);
(9)int sem_post (sem_t *__sem);
(10)int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval);

2.1 无名信号量

用途:线程,亲缘关系进程同步
常见用法是即将保护的变量放到sem_wait和sem_post中间所产生的临界区内。

常见函数说明:
/*
功能:初始化信号量
pshared==0用于同一个进程的多线程的同步。
pshared>0用于多个相关进程间的同步(由fork产生的亲缘进程)
*/
int sem_init(sem_t *sem, int pshared, unsigned int value);

/*
用途:销毁信号量
*/
int sem_destroy(sem_t *sem);

/*
用途:获取信号量当前值
若有1个或更多的线程或进程调用sem_wait阻塞在该信号量上,该函数返回两种值:
1)返回0
2)返回阻塞在该信号量上的进程或线程数量
*/
int sem_getvalue(sem_t *sem, int *sval);

/*
用途:相当于P操作,即申请资源。阻塞函数 
若sem>0,这么它减1并立刻返回。
若sem==0,则睡眠直至sem>0,此时立刻减1,之后返回。
*/
int sem_wait(sem_t *sem); //阻塞函数 
int sem_trywait(sem_t *__sem);

/*
用途:相当于P操作,即申请资源。非阻塞的函数 
若sem>0,这么它减1并立刻返回。
若sem==0,不是睡眠,而是返回一个错误EAGAIN。
*/
int sem_trywait(sem_t *sem);  


/*
用途:相当于V操作,释放资源
把指定的信号量sem的值加1;
呼醒正在等待该信号量的任意线程。
*/
int sem_post(sem_t *sem);

测试程序1:使用信号量实现多线程同步(线程执行次序随机)

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>

// 被保护的全局变量
int number; 

//信号量
sem_t semid;

void* thread_one(void *arg)
{
    sem_wait(&semid);
    printf("thread_one have the semaphoren\n");
    number++;
    printf("number = %d\n",number);
    sem_post(&semid);
}

void* thread_two(void *arg)
{
    sem_wait(&semid);
    printf("thread_two have the semaphore \n");
    number--;
    printf("number = %d\n",number);
    sem_post(&semid);
}

int main(int argc, char *argv[])
{
    number = 1;
    pthread_t tid1, tid2;
    sem_init(&semid, 0, 1);
    pthread_create(&tid1,NULL,thread_one, NULL);
    pthread_create(&tid2,NULL,thread_two, NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    printf("main running...\n");
    return 0;
}
编译执行:
g++ test.cpp -lpthread
./a.out 

测试程序2:使用信号量实现多线程同步(线程执行次序指定)

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>

// 被保护的全局变量
int number; 
sem_t semid1, semid2;
void* thread_one(void *arg)
{
    sem_wait(&semid1);
    printf("thread_one have the semaphore\n");
    number++;
    printf("number = %d\n",number);
    sem_post(&semid1);
}

void* thread_two(void *arg)
{
    sem_wait(&semid2);
    printf("thread_two have the semaphore \n");
    number--;
    printf("number = %d\n",number);
    sem_post(&semid2);
}

int main(int argc, char *argv[])
{
    number = 1;
    pthread_t tid1, tid2;
    sem_init(&semid1, 0, 1);
    sem_init(&semid2, 0, 0);
    pthread_create(&tid1,NULL,thread_one, NULL);
    pthread_create(&tid2,NULL,thread_two, NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    printf("main running...\n");
    sem_destroy(&semid1);
    sem_destroy(&semid2);
    return 0;
}

测试程序3:无名信号量在亲缘进程间的同步


#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 #include <stdlib.h>

int main(int argc, char **argv)
{
    int fd, i, nloop=10, zero=0, *ptr;
    sem_t mutex;
    //open a file and map it into memory
    fd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU);
    write(fd,&zero,sizeof(int));
    ptr = (int*)mmap( NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    /* create, initialize semaphore */
    if( sem_init(&mutex,1,1) < 0) //
    {
        perror("semaphore initilization");
        exit(0);
    }
    if (fork() == 0)
    { /* child process*/
        sem_wait(&mutex);
        for (i = 0; i < nloop; i++)
        {
            printf("child: %d\n", (*ptr)++);
        }
        sem_post(&mutex);
        exit(0);
    }
    /* back to parent process */
    sem_wait(&mutex);
    for (i = 0; i < nloop; i++)
    {
        printf("parent: %d\n", (*ptr)++);
    }
    sem_post(&mutex);
    exit(0);
}

编译执行:
g++ test.cpp -lpthread
./a.out 

 

2.2 有名信号量

用途:线程,亲缘关系进程,无亲缘关系进程同步
有名信号量的是把信号量的值保存在文件中

/*
用途:打开信号量文件
name是文件的路径名,在linux中sem都是创建在/dev/shm目录下。
name可以写成“/mysem”或“mysem”,创建的文件都是“/dev/shm/sem.mysem”,不要写路径。
oflag有O_CREAT或O_CREAT|EXCL两个取值;
mode控制新的信号量的访问权限;
value指定信号量的初始化值。
使用时包含头文件:
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
*/
sem_t *sem_open(const char *name, int oflag, mode_t mode , int value);

其他函数同匿名信号量。


3.System V信号量

        System V信号量是SYSTEMVIPC的组成部份,System V信号量在内核中维护,其中包括二值信号量、计数信号量、计数信号量集。
系统中记录信号量的数据结构(structipc_idssem_ids)坐落内核中linux查看信号量命令,系统中的所有信号量都可以在结构sem_ids中找到访问入口。
struct semid_ds {
    struct ipc_permsem_perm ;
    struct sem* sem_base ; //信号数组指针
    ushort sem_nsem ; //此集中信号个数
    time_t sem_otime ; //最后一次semop时间
    time_t sem_ctime ; //最后一次创建时间
};
常见api说明:
(1)semget
/*
功能:创建信号量或获得在系统已存在的信号量,不同进程使用同一个信号量通配符来获得同一个信号量
返回值是一个称为信号量标示符的整数,semop和semctl函数将使用它。
key:所创建或打开信号量集的通配符。须要是惟一的非零整数。
nsem:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。通常取值为1.
oflag:调用函数的操作类型,也可用于设置信号量集的访问权限,SEM_R(read)和SEM_A(alter),也可以是IPC_CREAT或IPC_EXCL
*/
int semget (key_t key, int nsem, int oflag);


(2)semctl
/*
功能:初始化信号量
使用semctl()函数的SETVAL操作
当使用二维信号量时,一般将信号量初始化为1
sem_id是由semget返回的信号量标示符。
sem_num是信号量集中的某一个资源
cmd:表示即将采取的动作。最常用的两个值如下:
SETVAL:拿来把信号量初始化为一个已知的值。这个值通过unionsemun中的val成员设置。其作用是在信号量第一次使用之前对它进行设置。
IPC_RMID:用于删掉一个无需继续使用的信号量标志符。
union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO */
};
*/
int semctl(int semid, int semnum, int cmd, ...);

3、semop
/*
功能:进行信号量的PV操作
实现进程之间的同步和互斥的核心部分
参数semid是一个通过semget函数返回的一个信号量标示符
参数opsptr是一个表针,指向一个信号量操作字段
参数nops标注了参数semoparray所指向链表中的元素个数
struct sembuf{  
    //除非使用一组信号量,否则它为0  
    short sem_num;
    //信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
    // 一个是+1,即V(发送信号)操作。  
    short sem_op;
    short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,  
    //并在进程没有释放该信号量而终止时,操作系统释放信号量  
};
*/
int semop (int semid, struct sembuf * opsptr, size_t nops) ;

相关命令:

(1)查看信号量

ipcs -s 

(2)删除信号量组

ipcrm sem

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

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

相关文章

ble系统知识介绍(较为完整,持续更新中)

BLE学习 现在网上关于BLE系统的学习资料实在是太少了&#xff0c;因此本文希望能够聚集一些资料能够系统的入门BLE,本文翻译自Bluetooth_LE_Primer_Paper,还有一些网上的一些资料,如果侵害到了某些作者的权益请及时联系我 参考资料和链接 Bluetooth_LE_Primer_Paper_3MtXws-zP…

GitOps 实践之渐进式发布

本文作者&#xff1a;陈钧桐 腾讯云 CODING DevOps 高级解决方案架构师&#xff0c;从事多年技术布道工作&#xff0c;对于云原生时代下企业数字化转型、IT 与 DevOps 建设、价值流体系搭建等有丰富的经验&#xff0c;曾为多家大型企业提供咨询、解决方案以及内训服务。既关注工…

【Python小技巧】加密又提速,把.py文件编译为.pyd文件(类似dll函数库),你值得拥有!

文章目录 前言一、常见的Python文件格式有哪些&#xff1f;二、准备编译环境1. 安装cython2. 安装Microsoft C 生成工具 三、编译.py文件为.pyd文件1. 编辑原始.py文件2. 准备setup.py文件3. 进行编译 四、测试总结 前言 Python的脚本文件是开源的&#xff0c;若直接发布&#…

i.MX RT1010跨界MCU上手体验(上)

由于项目需要性价比高一些的高性能MCU&#xff0c;了解到NXP的RT1010主频高达500MHZ的MCU&#xff0c;半个月以前已经拿到官方Demo板了&#xff0c;今天抽空上电体验下&#xff0c;在此记录。这颗芯片的优势是主频高&#xff0c;功能全&#xff0c;价格合理&#xff0c;但是需要…

第六章 方法区

文章目录 前言一、&#x1f6fa; 栈、堆、方法区的交互关系二、&#x1f68e; 方法区的理解1、方法区在哪里2、方法区的演变过程 三、&#x1f697; 设置方法区的大小与 OOM1、设置方法区内存的大小2、使用CGLib 让方法区OOM3、如何解决 OOM4、方法区的内部结构5、non-final 的…

利用提示工程优化软件架构:ChatGPT的应用

ChatGPT时代的软件架构全生命周期 简介 在如今日新月异的技术环境中&#xff0c;软件架构师必须不断地寻找和采纳新的工具和方法&#xff0c;以优化开发过程&#xff0c;提高效率&#xff0c;并保证最终产出的质量。其中&#xff0c;人工智能&#xff08;AI&#xff09;已经成…

《淘宝技术这十年》读书笔记

一. 分布式时代 在系统发展的过程中&#xff0c;架构师的眼光至关重要&#xff0c;作为程序员&#xff0c;只要把功能实现即可&#xff0c;但作为架构师&#xff0c;要考虑系统的扩展性、重用性&#xff0c;对于这种敏锐的感觉&#xff0c;有人说是一种“代码洁癖”。淘宝早期…

使用双屏时两个屏幕的色调、亮度不一样如何设置?

当使用双屏时&#xff0c;即使两个屏幕的型号一致也可能存在色差的问题&#xff08;色调不一致&#xff0c;亮度不一致&#xff09;&#xff0c;以下是解决此问题的方法。 Step1.同时按下两个屏幕下方的ok按钮 Step2.此时会进入显示器的OSD界面 Step3.通过按键切换菜单 Step4.…

节省35% MCU开发成本的红外智能洗手器运用方案,N9300-S16音乐芯片

随着全国人民生活水平的逐步提升以及近期疫情影响&#xff0c;公民的健康保护意识也越来越强&#xff0c;洗手液越来越被人们重视以及提倡&#xff0c;即时在受疫情影响是2022年洗手液市场规模也是上升至恐怖34亿元产值&#xff1b;而近年来自动感应洗手液器凭借实用性、便携性…

APP测试面试题快问快答(三)

11. App安装测试的主要内容有哪些&#xff1f; App是客户端程序&#xff0c;客户端程序就需要进行安装才能使用&#xff0c;因此需要测试安装、卸载、升级测试 关注点&#xff1a;正常场景、异常场景。 正常场景&#xff1a; 1. 在不同的操作系统上安装 2. 从不同的安装渠…

windows10安装ElasticSearch

一 安装 Java环境 ElasticSearch使用Java开发的&#xff0c;依赖Java环境&#xff0c;安装 ElasticSearch 之前&#xff0c;需要先安装一个较新版本的 Java&#xff0c;jdk 1.8版本太低了&#xff0c;需要安装jdk 11或更高版本。 Java安装方法请参考 Java 15环境安装 。 二 …

详解字典树原理,代码分析leetcode208. 实现 Trie (前缀树)

0、引言 本文介绍一种能够偶快速查找字符串的树形数据结构-----字典树。介绍其原理&#xff0c;以及通过leetcode208题目这个实例&#xff0c;用数组动手实现一棵字典树&#xff0c;并完成其增、查字符串、查字符串前缀的功能。 1、字典树的应用场景 询问一个单词b&#xff0c…

Mujoco 加载机器人模型(三)

目录 .1 简介 1.1 urdf概述 ​编辑 1.2 导出urdf为可用的xml​编辑 1.3 导出测试​编辑 .2 修改 2.1 添加平面和物体 2.2 关节修改 2.2.1 group 2.2.2 关节修改 2.2.3 关节 解压提供的ur5后 修改compiler的 meshdir路径 <mujoco model"ur5"><compi…

一条耗时100ms的SQL把系统搞崩了

一个项目上线了两个月&#xff0c;除了一些反馈的优化和小Bug之外&#xff0c;项目一切顺利。前期是属于推广阶段&#xff0c;可能使用人员没那么多&#xff0c;当然对于项目部署肯定提前想到并发量了&#xff0c;所以早就把集群安排上&#xff0c;而且还在测试环境搞了一下压测…

2023年的深度学习入门指南(15) - 大模型的幻觉

2023年的深度学习入门指南(15) - 大模型的幻觉 大模型的能力最另人惊讶的&#xff0c;一个是强大的能力&#xff0c;另一个就是时不时一本正经地胡说八道。如果你用的是小一点的模型&#xff0c;可能还见过输出循环内容之类的情况。我们将这种生成不良内容的现象称为幻觉-hall…

3d动画用云渲染靠谱吗?

3d动画是一种利用计算机技术制作的动画形式&#xff0c;它可以模拟真实世界的物体和场景&#xff0c;创造出各种惊人的效果和视觉体验。3d动画广泛应用于影视、游戏、广告、教育等领域&#xff0c;成为当今最流行的艺术表现形式之一。据统计&#xff0c;2019年全球3d动画市场规…

吴恩达老师《机器学习》课后习题1之线性回归

在学习这些内容之前&#xff0c;需要学习python数据分析相关内容&#xff1a; numpy&#xff1a;科学计算库&#xff0c;处理多维数组&#xff0c;进行数据分析 pandas&#xff1a;基于numpy的一种工具&#xff0c;该工具是为了解决数据分析任务而创建的 matplotlib&#xff1a…

Atcoder Beginner Contest 297

A - Double Click AC代码&#xff1a; #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N110; int t[N]; int main() {int n,d;cin>>n>>d;for(int i1;i<n;i) cin>>t[i];bool flagfalse;i…

数据结构05:树的定义与双亲表示法[持续更新中]

参考用书&#xff1a;王道考研《2024年 数据结构考研复习指导》 参考用书配套视频&#xff1a;5.1.1 树的定义和基本术语_哔哩哔哩_bilibili 特别感谢&#xff1a; Chat GPT老师[部分名词解释、修改BUG]、BING老师[封面图]~ 备注&#xff1a;博文目前是未完成的状态&#xff…

【数据结构】哈希表(Map和Set)

文章目录 Map和Set模型MapTreeMap和HashMap对比Entry<K,V>常用方法 SetTreeSet和HashSet对比常用方法 OJ练习只出现一次数字复制带随机指针的链表宝石与石头坏键盘打字前K个高频单词 哈希表哈希表所用数据结构解决哈希冲突闭散列开散列 避免哈希冲突哈希函数设计负载因子…