聚合国内IT技术精华文章,分享IT技术精华,帮助IT从业人士成长

unix 类系统中的进程同步方式总结

2013-06-20 15:31 浏览: 847965 次 我要评论(0 条) 字号:

我们把异步环境下的一组并发进程因直接制约而互相发送消息、进行互相合作、互相等待,使得各进程按一定的速度执行的过程称为进程间的同步。
具有同步关系的一组并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件。 如果我们对一个消息或事件赋以唯一的消息名,则我们
可用过程 wait (消息名)  表示进程等待合作进程发来的消息,而用过程 signal (消息名) 表示向合作进程发送消息。
(引自百度百科)

进程间的同步方式:
为了实现进程互斥地进入自己的临界区,操作系统中设置专门的同步机制来协调各进程间的运行。所有的同步机制都应遵循下书四条准则:
1)空闲让进
2)忙则等待
3)有限等待
4)让权原则。当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入“忙等”状态。

1.单CPU (UP)机器利用sleep/wakeup函数对实现同步机制。
函数sleep是一个内部的内核例程,它挂起调用它的进程,直到指定的事件发生为止。这是一个以内核态运行的进程自愿出让控制权,允许自己被抢占。
函数wakeup用于发出一个特定事件已经出现的信号,它使得所有等待该事件的进程被唤醒,并放回到运行队列中。事件用一个整数值来表示,它往往
是该事件相关的内核数据结构的地址。

void lock_object( char *flag_ptr)
{
    lock(&object_locking);        //自旋锁
     while (*flag_ptr)
           sleep(flag_ptr);
     *flag_ptr = 1;
    unlock(&object_locking);
}

void unlock_object( char *flag_ptr)
{
    lock( &object_locking );
    *flag_ptr = 0;
    wakeup( flag_ptr);
    unlock( &object_locking );
}

应为wakeup操作没有记忆,所以wakeup函数必须唤醒在同一事件上睡眠的所有进程。在多CPU系统上,即MP上sleep/wakeup机制不起作用。

2.SVR4.2 MP 提供了单独的执行进程同步的原语:同步变量。
因为同步变量不包含状态,所以可以把它们想成是sleep/wakeup的一种MP变形。相反,所需的任何状态信息都保存在外部标志或者计数器中。
同步变量的设计要同自旋锁配合工作。

同步变量被声明为sv_t类型,采用下面的函数可以给它分配空间和进行初始化:
sv_t *SV_ALLOC( int slpflag);
slpflag指定,如果需要为同步变量分配内存,那么是否能阻塞进程。

回收同步变量可以调用
void SV_DEALLOC( sv_t *svp );

内核希望单独等候的每一个事件都用一个不同的同步变量来表示,这就好比配合sleep如何使用唯一的事件参数。
void SV_WAIT( sv_t *svp, int pri, lock_t *lockp );

要触发在同步变量上的事件,可以使用下面的函数:
void SV_SIGNAL( sv_t *svp, int flags);
SV_SIGNAL与wakeup的相似之处在于,如果没有正在睡眠的进程,那么就对过去曾经执行过的操作没有记忆,调用什么也不做。
SV_SIGNAL只唤醒一个进程。如果要唤醒在事件上睡眠的所有进程,可以用同步变量的下列函数来实现:
void SV_BROADCAST( sv_t *svp, int flags);

如果在事件被触发之前出现了一个UNIX信号,那么下面的SV_WAIT变形会唤醒进程:
bool_t SV_WAIT_SIG( sv_t *svp, int pri, lock_t *lkp );
返回的代码表明发生了什么样的事件:如果出现了一个UNIX信号,那么它返回FALSE,如果出现了SV_SIGNAL或SV_BROADCAST,那么它返回TRUE.

3.采用信号量的同步
将信号量的值初始化为0,就可以用于进程同步,这样允许通过使用P操作让一个进程等待某个事件发生。既然信号量被初始化为0,那么进程将立即阻塞。
另一个进程使用V操作能够发出信号,表明事件已经结束。V操作导致正等待事件的进程被唤醒,并继续进行。因为即使在信号量上没有阻塞进程,
V操作也会给信号量加1,所以在前一个进程能够执行P操作之前出发事件会导致进程继续进行,不必等待。这是一种受欢迎的情形,因为它不需要额外的
协调工作,就能够处理在等候事件的进程同发信号表明该事件完成的进程之间本来就有的竞争条件。

进程1                                        进程2
p(s)       /*等待事件*/                    .
                                                  .
                                                  .
                                                V(s) /*触发事件*/


4.利用管程进行同步
管程为临界资源以及访问或者修改该资源的所有临界段提供了互斥机制,它还提供了在使用管程的诸进程之间进行同步的手段。一个管程可以想成是一个装有
资源的隔间。进程要访问资源,它必须首先进入隔间。通过一次只允许一个进程进入隔间,就做到了互斥。如果在管程已经投入使用的时候,别的进程试图进
入它,那就会被阻塞,直到使用管程的进程退出管程为止,或者在与管程关联的事件上等待。每个管程都可能有一个或者更多的事件,若干进程能够在这些事
件上等待。进程被阻塞这些事件上,直到在管程内执行的其他进程触发事件为止。根据定义,触发操作只能从管程内部完成。


5.利用事件计数进行同步
事件计数是一个非递减的正整数,在这个数值上定义了3种操作。操作advance(E)将事件计数E加1,这叫做出发事件。
操作await(E,V)致使调用进程被阻塞,指导事件计数E的值达到V为止。如果在调用await的时候,事件计数的值大于或等于V,那么进程继续执行,而不会阻塞,
因为事件是以前触发的。事件计数的当前值可以用read(E)来读取。在创建事件计数的时候,它被初始化为0,而且在数值上永远不会减少。假定保存事件计数值
得存储器位置足够大,于是事件计数在其整个生命期中,一直都不会溢出(通常一个32位的无符号整数就够了)。

有关代码示例,请参见后面的随笔。

martin_yahoo 2013-06-20 13:49 发表评论


网友评论已有0条评论, 我也要评论

发表评论

*

* (保密)

Ctrl+Enter 快捷回复