Linux--进程间通信之信号量(system V版本的信号量)

本文介绍了Linux中System V版本的信号量,作为进程间通信的一种方式。首先阐述了临界资源、临界区、同步与互斥的基本概念,然后详细讲解了信号量的本质、常见操作,包括P操作和V操作,并强调了其原子性。接着,讨论了System V信号量集的创建、删除、获取和初始化等API。最后,通过一个示例展示了信号量在控制临界资源访问中的应用,即如何确保进程按顺序输出字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引入信号量之前,我们先要了解四个基本概念,什么是临界资源与临界区,什么是同步与互斥。

1 基本概念

1.1 临界资源与临界区的概念

1.临界资源:对于某些共享资源,一次仅允许一个进程访问,这个资源就称为临界资源。
2.临界区:访问临界资源的那些代码称为临界区。

1.2 同步与互斥

1.互斥:对于某种资源,如果有一个进程正在访问该资源,则其它的进程必须等待,当那个进程访问完成后其它进程才能访问。
2.同步:某些进程的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。

同步最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。

2 信号量

1.本质:信号量本质上是一个表示临界资源数目的一个计数器。
2.底层:一个计数器加上一个等待队列。

struct semaphore
 {
       int value;    //计数器
       pointer_PCB queue;   //等待队列
}

3.信号量里有一个特殊的信号量:二元信号量
(1)二元信号量的值非0即1。
(2)二元信号量的本质就是一把互斥锁。
4.在进程间通信里,信号量本身并不具备传输数据的能力,而是通过控制其它的通信资源来实现进程间通信的同步与互斥。

2.1 信号量值的含义

若用S表示信号量
(1)S > 0 ,表示剩余临界资源的数目
(2)S = 0,表示没有可用资源,也没有等待进程
(3)S < 0,|S|表示等待进程的数目

注意:这里的S表示的信号量是通用的信号量,但是对于system V版本的信号量来说,信号量没有负值,当信号量的值等于0的时候,需要申请该资源的进程挂起等待。

2.2 信号量常见的操作

1.信号量常见的操作有P操作和V操作
(1)P操作
对该信号量的值减1,以表明对应申请得到资源。
(2)V操作
对该信号量的值加1,以表明该用户归还申请得到的资源。
2.因为信号量是用来实现同步与互斥的,所以对信号量的操作也必须是原子的。
3.P、V操作具有原子性,因为信号量能被不同进程看到,信号量本身也是一种临界资源。

2.3 信号量集相关的API

因为对于system V版本的信号量来说,创建信号量是以信号量集的方式创建的

1.创建信号量集
(1)通过semget函数

#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);

(2)参数解析:

key:通过ftok函数产生一个唯一标识信号量集的标识符
nsems:由于该函数是创建一个信号量集,一个集合必须知道元素的个数,这里的nsems指的就是创建的信号量集中信号量的个数。
semflg:与消息队列和共享内存里的用法一致,当为IPC_CREAT表示不存在就创建存在就打开,当同时使用IPC_CREAT和IPC_EXCL表示不存在就创建,存在就失败。

(3)使用示例:

//创建包含num个信号量的信号量集,返回值为信号量集唯一标识semid
int  SemCreate(int num)
{
    key_t key = ftok(PATHNAME,PROJ_ID);
    if(key < 0)
    {   
        perror("ftok");
        return -1;
    }   

    int semid = semget(key,num,fIPC_CREAT | IPC_EXCL | 0666);
    if(semid < 0)
    {   
        perror("semget");
        return -1;
    }   
    return semid;
}

2.删除信号量集
(1)通过semctl函数

int semctl(int semid, int semnum, int cmd, ...);

(2)参数解析:

semid:信号量集的唯一标识,表示对哪个信号量集执行相关操作
semnum:表示信号量集中某个信号量的下标(序号)
cmd:执行的相关命令,当cmd为IPC_RMID时,第二个参数无效(因为对整个信号量集都删除,对哪个信号量标号也就不关心了),表明删除信号量集

(3)使用示例:

int DestroySem(int semid)
{
    //因为删除信号量集,所以第二隔参数任意
    int ret = semctl(semid,0,IPC_RMID);
}

3.获得信号量集
(1)通过semget函数

#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值