初步接触,若有不足之处,请各位不吝赐教。谢谢!
首先介绍:信号量
信号量包括整型信号量、结构型信号量、二值信号量。
①
整型信号量
最初,将信号量定义为一个共享的整型量,它保存可供使用的唤醒数目。如果信号量的值为0,表示没有保存唤醒;如果它的值大于0,表示有一个或多个保留的唤醒。
对信号量的操作有以下限制:
1、信号量可以初始化为一个非负值。
2、只能由P和V两个操作来访问信号量。
P操作最初源于荷兰语proberen,表示测试;V操作源于荷兰语verhogen,表示增加。请读者注意,在有些书上将P操作称作wait或者DOWN操作,将V操作称作signal或者UP操作。
P和V操作定义的伪代码形式如下:
P(S)
//测试信号量S的值是否大于0,若是,则S的值减1,程序向下执行,如果不大于0,则循环测试。
{
while (S <= 0);//不执行任何操作
S--;
}
V(S)//只是简单地把S的值加1
{
S++;
}
P和V操作都是原语,即单个的、不可分割的原子操作。
(原语:是机器指令的延伸,往往是为完成某些特定的功能而编制的一段程序,它在执行时不可分割、不可中断。即一个操作中的所有动作要么全做,要么全不做。执行原语时要屏蔽中断,以保证其操作的不可分割性。)
一般使用方式是:当多个进程互斥进入临界区时,需要设置一个信号量mutex,其初值为1,这些进程进入、使用和退出临界区的构造形式是一样的。下面是其中任一进程Pi利用信号量实现互斥的伪代码形式:
do
{
P(mutex);
临界区
V(mutex);
其他代码区
} while (1);
主要缺点:忙式等待问题:当一个进程处于临界区时,其它试图进入临界区的进程必须在入口处持续进行测试,很显然,这种循环测试、等待进入的方式在单CPU多到程序系统中存在很大问题,因为忙式等待要消耗CPU的时间,即使其它进程想用CPU做有效工作,也无法实现。这种类型的信号量也称“转锁”(Spinlock),因为当进程等待该锁打开时要“原地转圈”。然而,在多处理器系统中转锁仍得到应用。
②
结构型信号量
又称为记录型信号量、计数信号量,一般是由两个成员组成的数据结构。其中一个成员是整型变量,表示该信号量的值另一个是指向PCB(进程控制块,进程存在的唯一标识)的指针。当多个进程都等待同一个信号量时,它们就排成一个队列,由信号量的指针项指示该队列的队首,而PCB队列是通过PCB自身所包含的指针项进行链接的。最后一个PCB(即队尾)的链接指针为0。
可以将信号量定义为如下所示的一个C语言结构:
typrdef struct
{
int value;
struct PCB *list;
}semaphore;
信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量
当它的值小于0时其绝对值表示等待使用该资源的进程个数,即在该信号量队列上排队的PCB的个数。
对信号量的操作有如下严格的限制:
1、信号量可以赋初值,且初值为非负数。信号量的初值可由系统根据资源使用情况和使用需要来确定。在初始条件下,信号量的指针项可以置为0,表示队列为空。
2、在使用过程中信号量的值可以修改,但只能由P和V操作访问,不允许通过其他方式查看或操纵信号量。
设信号量为S,对S的P操作记为P(S),对S的V操作记为V(S)。
P、V操作的定义分别如下:
void P(semaphore S)
{
S.value--;//信号量的值S.value减1
if (S.value < 0)
//如果其值大于0,则该进程继续运行;如果其值小于0,则把该进程的状态置为阻塞,把相应的PCB链入该信号量队列的队尾,
//放弃处理机,进行等待(直至其它进程在S上执行V操作,把它释放出来为止)
{
把这个进程加到S.list队列;
block();//block操作挂起调用它的进程
}
}
void S(semaphore)
{
S.value++;//信号量的值S.value加1
if (S.value <= 0)
// 如果其值大于0,则该进程继续运行;如果其值小于等于0,则释放信号量队列上的第一个PCB(即信号量指针项所指向的PCB)
// 所对应的进程Q(把阻塞状态改为就绪状态),执行V操作的进程继续运行。
{
从S.list队列中移走进程Q;
wakeup(Q);//wakeup(Q)操作恢复被阻塞进程Q的执行
}
}
block()操作和wakeup(Q)操作被操作系统作为基本系统调用。
在具体实现时应注意P,V操作都是原语。
上述阻塞状态进程链入相应队列末尾,以及将队列的队首进程从阻塞队列中移至就绪队列中采用的方法是FIFO(即先进先出)策略。然而,具体实现并不限于此,管理队列可以采用任何一种链接策略。信号量使用是否正确与信号量队列的排队策略无关。
③
二值信号量
它是上述信号量的一种特例,它的值只能在0和1之间选择。依赖于底层的硬件体系结构,二值信号量比计数信号量更容易实现二值信号量类似互斥锁。
二值信号量及其操作的定义用C语言描述如下:
typedef struct
{
enum{
false,true}value;//枚举量
struct PCB *list;
}B_semaphore;
void P_B(B_semaphore S)
{
if (S.value == true)
S.value = false;
else