sem_semtimedwait函数不会执行PV操作吗?

版权声明:本文为博主原创文章,未经博主允许不得转载。 /zyl_/article/details/

信号量的本质是一种数据操作锁(一个计数器而已)只是外部资源的标识;
当请求一个使用信号量来表示资源时,进程先要看信号量的值来判断是否可用,大于0就表示可以请求,等于0就是没有资源可用,进程会进入睡眠状态可用直至有资源。
信号量其实没有数据交换的功能,他是控制其他通信文件来实现进程间的通信;

二、为什么要用信号量?

为防止出现因多个程序同时访问一个共享资环二引发的问题,因此:信号量的作用就是:在任一时刻只能有一个执行线程访问代码的临界区;

三、什么是临界区,临界资源?

临界资源:不同的进程运行时看到共同的资源;
临界区:访问临界资源时的程序代码

首先:在信号量中是怎么操作的?
P(sv):如果sv的值大于0,就给它减1;如果它的值为0,就挂起该进程的执行;
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待而别挂起,就给它加1;
1、创建一个信号量的集合

返回值:成功返回sem_id,失败-1;
nsems:因为在信号量中,信号量只能用集合来创建,所以这个是你创建信号量集合的个数;
semflg:是创建信号量集合的关键字,创建时:一般是IPC_CREAT|IPC_EXCL没有信号量的话,创建一个新的,有的话返回出错,接受时:IPC_CREAT,没有直接创建,有直接获取,在semflg中就只有这两种组合;
2、信号量的P和V操作:

返回值:成功0,失败-1;
第二个参数是一个结构体指针:

sem_num:信号量集合在系统中类似于一个数组的存在,所以它的数组下标就是用来访问它的数;
sem_op:是信号量的操作方式(P/V操作),P操作是-1,V操作是1;
IPC_NOWAIT:对信号量的操作不能满足时,semop()不会阻塞,而是立即返回,同时设定错误信息。
SEM_UNDO:程序结束时(不管正常还是不正常),保证信号值会被设定semop()调用之前的值,这样做的目的在于避免程序在异常情况下结束未解锁,就会导致死锁;
3、信号量的摧毁与初始化

这个函数我们都知道是可变参数,所以:

在系统函数中它的大小就是4个字节,所以,我们自己定义一个占4个字节的联合体就可以了,不让你=系统无法判定大小,编译通不过;

信号量的生命周期和msgqueue一样都是随内核,所以当你第一次运行成功够,没有手动删除sem第二次就会出错;
所以必须在root 权限下查看和删除:

子进程打印AA,父进程打印BB,利用sem来控制:

今天,我们来学习一下PV操作的信号量

我们知道任何事物的诞生都有它的生活原型,PV操作也不例外,那么PV操作来自哪里呢?正是来自于我们日常的交通工具——火车!

我们都知道去年7.23动车事故让一个名词火了一把,那就是闭塞系统。所谓闭塞系统,本文简单说一下它的功能,它就是保证在一段时间内,一条铁轨的某一段距离内,只能有一辆火车在开动。而为了保证闭塞系统的实现,这里面就用到了信号灯,这个信号灯就是通过火车倾轧铁轨的时候来开启和关闭的。而操作系统中PV所用到的“信号量”正是源于此。好了知道了信号量的来源,我们再来深化一下这个概念,信号量就是标识和限定PV操作中资源状态的一个变量。

我们知道PV操作一般涉及两种信号量,即同步信号量和互斥信号量

要了解“同步信号量”的概念,我们可以通过一个简单的实例来说明,例如:有一队士兵在徒步行军的过程中,每个士兵之间一般会有间距,而这个间距的范围是多少呢?我们可以想象一下,这个间距必须是合理的,不能太大,也不能太小,否则就会出现碰撞和掉队。那么我们如何来控制这个间距呢?这时我们就可以用两个变量来标识,分别是最大间距和最小间距。也就是说我们用两个变量来保证间距,而这个时候的变量就是所谓的“同步信号量”,因为是同时起作用的。

了解“同步信号量”之后我们再来讲一下“互斥信号量”,同样,我们也举个例子:比如还是那一队士兵,在行进的过程中需要经过一个桥,但是这个桥的承重只能保证一个士兵通过,两个人以上就会导致桥的塌陷,这个时候我们也可以用一个变量来标识正在通过的士兵,很显然这个正在通过的士兵是一个而不是一个集合,那么士兵之间在过桥的时间和顺序上就是互斥的,而这个标识正在通过的士兵就就是所谓的“互斥信号量”。

理解了信号量的概念之后相信,对于PV操作,读者一定会有一个新的认识,那就是PV操作不过是一个合理的时候来更改信号量而已。


PV操作原语和信号量sem是计算机操作系统进程和线程同步的核心手段,虽然说起来只有句话,但有几个点非常容易引起模糊。先把PV操作的说明如下:

  1. 若sem 大于等于0,线程继续执行.

  1. 若sem 大于 0, 线程继续执行

  2. 若sem 小于等于0,唤醒阻塞队例的线程

问题和Java都提供了volatile关键字,估计是添加的新的指令来保证,不过还好,这是操作系统操心的事情,操作系统保证原语概念的完整 性。

信号量sem在PV操作里具有三元性质.

让我们来看一个具体的实例: 假设现在的执行场景是有三个线程A,B,C进入一个信号量为1的临界资源,

  1. 当线程A进入时,执行P操作, sem=0,线程A继续执行.

  2. 当线程B进入时,线程A假设仍在占用临界资源, B执行P操作,sem = -1,B进入等待队列。

  3. 当线程C进入时,线程A假设仍在占用临界资源, C执行P操作,sem = -2,C进入等待队列

通过以上的步骤可以发现:

1) 当sem > 0 时,表示可用的临界资源的数量

2) 当sem = 0时,表示无可用的资源,也没有阻塞的线程

3) 当sem <0 时,sem的绝对值表示阻塞队列的线程数

问题3.对V操作2,3步骤的解释

V操作的第2步,sem > 0 ,线程继续执行.有些人这个地方不解,sem > 0不是代表有资源可用吗?为什么不是唤醒其它的线程。其实正是sem >0 ,sem当前的意义是有资源可用,而没有阻塞的线程,所有根本不需要唤醒.

V操作的第3步,sem 小于等于0, 唤醒阻塞队例的线程. sem < 0很多人直觉认识都是没资源可用了,干吗还唤醒阻塞队列的线程(包括我)。通过问题2的分析,在这个时候sem代表的是阻塞队列的线程数 ,所以需要唤醒. 让我们接着问题2的步骤.

4) 线程A资源使用完,执行V操作,sem = -1, 唤醒阻塞队列的线程(假设FIFO),B线程进入临界资源开始执行,注意,B不会再执行P操作,因为进入阻塞队列前已执行.P,V操作必须成对执行。

5) B使用完资源后,执行V操作,sem = 0; 唤醒阻塞队列的线程,C线程进入临界资源开始执行,C也不会再执行P操作

PV操作由P操作原语和V操作原语组成(原语是不可中断的过程)。对信号量进行操作,具体定义如下:

②如果s >= 0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
②如果S > 0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。
信 号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时, 表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。
一般来说,信号量S >= 0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的 进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S <= 0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。也就是说,有一个未被占用的资源就可以让一个阻塞的进程执行,而不是S为正是才可以执行。

进程(线程)之间的两种关系:同步与互斥。

所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行,各程序片段的运行次序没有要求。

所谓同步,是指散布在不同进程之间的若干程序片断,它们的运行必须严格按照规定的先后次序来运行,这种先后次序依赖于要完成的特定的任务。  

显然,同步是一种更为复杂的互斥,而互斥是一种特殊的同步。也就是说互斥是两个线程之间不可以同时运行,他们会相互排斥,必须等待一个线程运行完毕,另一个才能运行,而同步也是不能同时运行,但他是必须要安照某种次序来运行相应的线程(也是一种互斥)! 

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。  

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

我要回帖

更多关于 sem_timedwait 的文章

 

随机推荐