Linux下信号量使用总结

article/2025/11/7 6:09:16

目录

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://chatgpt.dhexx.cn/article/iMkplRbs.shtml

相关文章

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…

IntValue()方法 和 ValueOf()方法

intValue() 1.intValue()是java.lang.Number类的方法&#xff0c;Number是一个抽象类。Java中所有的数值类都继承它。也就是说&#xff0c;不单是Integer有intValue方法&#xff0c;Double&#xff0c;Long等都有此方法。 2.此方法的意思是&#xff1a;输出int数据。每个数值类…

Double取值intValue()与doubleValue()

描述一个之前没注意&#xff0c;手误造成的bug。 可以看出&#xff0c;Double调用intValue()结果类似于RoundingMode.DOWN。 调用doubleValue()才是取double真实值。

java中valueof_JAVA中intValue()和ValueOf()什么意思,还有Value什么意思

展开全部 intValue()和ValueOf()是数据类62616964757a686964616fe59b9ee7ad9431333366306538型转化的两个方法。 intValue() 如Integer类型&#xff0c;就会有intValue()方法&#xff0c;意思是说&#xff0c;把Integer类型转化为Int类型。 valueOf() 如String就有valueOf()方法…

IDEA告警:Unnecessary unboxing ‘xxx.intValue()‘

显式编码拆箱已包装的原始数值。在Java5及以上的版本&#xff0c;拆箱是不必要的&#xff0c;可以安全地删除。那么 JDK5 到底做了啥&#xff1f; 自动装箱&#xff08;auto-boxing&#xff09;与自动拆箱&#xff08;auto-unboxing&#xff09; Java语言的基本类型都有包装&…

latex自定义插入空行或者空格

空行有几种方法&#xff1a; 1.~\\ 2.\\[行距] 例如&#xff1a;\\[3pt] 最后&#xff0c;我的选择是&#xff1a; \vspace*{n\baselineskip}空格&#xff1a;

latex中加入空白行的一种方法

在两行文字中间加入“~\\”就可以达到空行的目的了 如图所示&#xff0c;上面是加入“~\\”&#xff0c;下图是得到的结果

latex句首缩进空格

有时候想要再句首加空格&#xff0c;但是会被自动忽略&#xff0c;于是可以使用命令 \hspace*{0.6cm} 例如&#xff1a; $initialize the initial solutions w,precision,max_iters,\\ while (w< precision) and (iters < max_iters):\\\hspace*{0.6cm} grad \gets \…

LaTeX数学公式中的空格

两个quad空格 a \qquad b 两个m的宽度 quad空格 a \quad b 一个m的宽度 大空格 a\ b 1/3m宽度 中等空格 a\;b 2/7m宽度 小空格 a\,b 1/6m宽度 没有空格 ab 紧贴 a\!b 缩进1/6m宽度 \quad、1em、em、m代表当前字体下接近字符‘M’的宽度&#xff08;approximately the …

Latex空格

Latex空格分许多种&#xff0c;分别有&#xff1a; 源代码 \documentclass[UTF8]{ctexart}\begin{document}\begin{tabular}{|l|l|l|l|} \hline 类别 & 用法 & 含义 & 效果\\ \hline 两个quad & a$\backslash$qquad b & 两个m的宽度 & a\qquad b \\ \h…