信号量的使用和原理
信号量和信号是不同的IPC通信机制,信号量是在进程之间传递是一个整数值,信号量只有三种操作可以进行:初始化,P操作,V操作,我们看一下具体的使用函数和数据结构。
#include<sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);//创建新信号量或获取已有的信号量
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);//改变信号量的值
struct sembuf{
short sem_num;
short sem_op;//通常是两个数,一个是-1,即P操作,一个是+1,即V操作。
short sem_flg;//跟踪信号
};
我们通过semget()函数获取或者创建一个信号量,并返回一个信号量id,有了这个id,我们就可以通过semop()函数进行V和P的操作。
由于信号量只能进行两种操作即"等待"和"发送",即P(sv)和V(sv),他们的行为是这样:
- P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
- V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1。
- 举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,他将得到信号量,并可以进如临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会挂起以等待第一个进程离开临界区并执行(sv)释放信号。
这三种操作都是原子操作,我们通常用信号量来进行并发和同步的控制。
信号量的分类
Linux提供两种信号量
- 内核信号量:由内核控制路径使用
- 用户态进程使用的信号量:这种信号量又分为POSIX信号量和SYSTEM V信号量
- POSIX辛信号量又分为有名信号量和无名信号量
- 有名信号量:其值保存在文件中,所以它可以用于线程也可以用于进程间同步
- 无名信号量:其值保存在内存。
POSIX信号量和SYSTEM V信号量的比较
-
对POSIX来说,信号量是个非负数。常用于线程间同步
而SYSTEM V信号量则是一个或者多个信号量集合,他对应的是一个信号量的结构体,这个结构体为SYSTEM V IPC服务的,信号量只不过是它的一部分。常用语进程间同步。 -
POSIX信号量的引用头文件是<semaphore,h>,而SYSTEM V信号量的引用头文件是<sys/sem.h>
-
从使用的角度,System V信号量是简单的。比如,POSIX信号量的创建和初始化PV操作就很方便。
不免要提一下互斥锁Mutex,信号量可以是非负整数,互斥锁只能是0和1两个值,我们可以将Mutex理解为特殊的信号量。
在大部分情况下,用互斥锁来做并发的控制会比信号量更方便。
什么是信号量
- 信号量又称为信号灯,它用来协调不用进程间的数据对象,而最主要的应用是共享内存方式的进程间通信。
- 本质上,信号量时一个计数器,他用来记录某个资源(如共享内存)的存取状况。信号量的使用,主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。
- 信号量的值为正的时候,说明它空闲。所有的线程可以锁定而使用它。若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒。
信号量的注意事项
- 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要这一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能由一个执行线程访问代码的临界区域
- 临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就说信号量临界区是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就说信号量是用来协调进程对共享资源的访问。
- 信号量时一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P-信号变量)和发送(即V信号变量)信息操作。
- 最简单的信号量只能取0和1的变量,这也是信号量最常见的一种形式,叫做二进制信号量。而可以取多个正整数的信号量被称为通用信号量
网友评论