EDU511 国际专业IT教育服务门户 |
|
|
Solaris2.4 多线程编程指南3--使用同步对象编程日期:08-06-02 22:40:30 点击: 来源:中讯IT 3 使用同步对象来编程 本章定义了四种可用的同步类型,并且讨论实现同步的注意事项。 互斥锁(mutex) 条件变量(condition variable) 多读单写锁(multi-read,single-write lock) 信号量(semophore) 进程间同步(process synchronization) 同步原语的比较(compare primitive) 同步对象是内存中的变量,你可以象访问一般的数据那样来访问它。不同进程内的线程可以通过共享内存中的同步变量来同步,即使这些线程互不可见。 同步变量可以放置在文件当中,可以比创建它的进程拥有更长的生命。 同步对象的类型包括: · 互斥锁 · 状态变量 · 读写锁 · 信号灯(信号量) 在下面几种情况下,同步是重要的: · 在两个或更多个进程内的线程可以合用一个同步变量。注意,同步变量应当被一个进程初始化,在第二次初始化时,该同步变量被设置为解锁状态。 · 同步是唯一保证共享数据持久的办法。 · 一个进程可以映射一个文件并通过一个线程将其加锁,修改完成之后,该线程释放文件锁并恢复文件。在文件加锁的过程中,任何程序中的任何 线程想要加锁时都会阻塞,直至解锁; · 同步可以保证易变数据的安全。 · 同步对于简单变量也是很重要的,例如整数。在整数没有和总线对齐或 大于数据宽度的情况下,读写一个整数可能需要多个内存周期。虽然在SPARC系统上不会发生这样的情况,但移植程序时不能不考虑这一点; 3.1互斥锁 用互斥锁可以使线程顺序执行。互斥锁通常只允许一个线程执行一个关键部分的代码,来同步线程。互斥锁也可以用来保护单线程代码。 Table 3-1 互斥锁函数 函数 操作 Mutex_init(3T) 初始化一个互斥锁 Mutext_lock(3T) 给一个互斥锁加锁 Mutex_trylock(3T) 加锁,如失败不阻塞 Mutex_unlock(3T) 解锁 Mutex_destroy(3T) 解除互斥状态 如果两个进程有共享且可写的内存,且做了相应的初始化设置后(参见mmap(2)),互斥锁可以实现进程间的线程同步。 互斥锁在使用前一定要初始化。 多线程等待一个互斥锁时,其获得互斥锁的顺序是不确定的。 3.1.1初始化一个互斥锁 mutex_init(3T) #include ( or #include ) int mutex_init(mutex_t *mp, int type, void * arg); 用mutex_init()来初始化一个由mp指向的互斥锁。Type可以是以下值之一(arg现在先不谈)。 USYNC_PROCESS 互斥锁用来同步进程间的线程。 USYNC_THREAD 互斥锁只用来同步进程内部的线程。 互斥锁也可以通过分配零内存来初始化,在此种情况下应当设定USYNC_THREAD。 一定不会有多个线程同时初始化同一个互斥锁。一个互斥锁在使用期间一定不会被重新初始化。 返回值--mutex_init()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。 EINVAL 非法参数 EFAULT mp或者arg指向一个非法地址。 3.1.2给互斥锁加锁 mutex_lock(3T) #include (or #include ) int mutex_lock(mutex_t *mp); 用mutex_lock()锁住mp指向的互斥锁。如果mutex已经被锁,当前调用线程阻塞直到互斥锁被其他线程释放(阻塞线程按照线程优先级等待)。当mutex_lock()返回,说明互斥锁已经被当前线程成功加锁。 返回值--mutex_lock()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。 EINVAL 非法参数 EFAULT mp指向一个非法地址。 3.1.3加非阻塞互斥锁 mutex_trylock(3T) #include (or #include ) int mutex_trylock(mutex_t *mp); 用mutex_trylock()来尝试给mp指向的互斥锁加锁。这个函数是mutex_lock()的非阻塞版本。当一个互斥锁已经被锁,本调用返回错误。否则,互斥锁被调用者加锁。 返回值--mutex_trylock()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。 EINVAL 非法参数 EFAULT mp指向一个非法地址。 EBUSY mp指向的互斥锁已经被锁。 3.1.4给互斥锁解锁 mutex_unlock(3T) #include (or #include ) int mutex_unlock(mutex_t *mp); 用mutex_unlock()给由mp指向的互斥锁解锁。互斥锁必须处于加锁状态且调用本函数的线程必须是给互斥锁加锁的线程。如果有其他线程在等待互斥锁,在等待队列头上的线程获得互斥锁并脱离阻塞状态。 返回值--mutex_unlock()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。 EINVAL 非法参数 EFAULT mp指向一个非法地址。 3.1.5清除互斥锁 mutex_destroy(3T) #include (or #include ) int mutex_destroy(mutex_t *mp); 用mutex_destroy()函数解除由mp指向的互斥锁的任何状态。储存互斥锁的内存不被释放。 返回值--mutex_destroy()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。 EINVAL 非法参数 EFAULT mp指向一个非法地址。 3.1.6互斥锁代码示例 Code Example 3-1 Mutex Lock Example Mutex_t count_mutex; Int count; Increment_count() { mutex_lock(&count_mutex); count=count+1; mutex_unlock(&cout_mutex); } int get_count() { int c; mutex_lock(&count_mutex); c=count; mutex_unlock(&count_mutex); return(c); } 在示例3-1中两个函数用互斥锁实现不同的功能,increment_count()保证对共享变量的一个原子操作(即该操作不可中断),get_count()用互斥锁保证读取count期间其值不变。 *为锁设置等级 你可能会需要同时访问两种资源。也许你在用其中一种资源时,发现需要另外一 种。就象我们在示例3-2中看到的,如果两个线程希望占有两种资源,但加互斥锁的 顺序不同,有可能会发生问题。在这个例子当中,两个线程分别给互斥锁1和2加锁, 在它们想给另外的资源加锁的时候,将会发生死锁。 Code Example 3-2 Deadlock Thread 1: Mutex_lock(&m1) /* use resource 1*/ mutex_lock(&m2); /* use resources 1 and 2*/ mutex_unlock(&m2); mutex_unlock(&m1); Thread 2: Mutex_lock(&m2); /*use resource 2*/ mutex_lock(&m1); /* use resources 1 and 2*/ mutex_unlock(&m1); mutex_unlock(&m2); 避免这个问题的最好办法是在线程给多个互斥锁加锁时,遵循相同的顺序。这种技术的一种实现叫"锁的等级":在逻辑上为每个锁分配一个数进行排序。 如果你已经拥有一个等级为I的互斥锁,你将不能给等级小于I的互斥锁加锁。 --------------------------------------- 注意--lock_init可以检测这个例子当中死锁的类型。避免死锁的最好办法是采用等 级锁:如果对互斥锁的操作遵循一个预先定义的顺序,死锁将不会发生。 --------------------------------------- 但是,这种技术并非总可以使用--有时你必须对互斥锁进行不按照预定义顺序的 操作。为了在这种情况下阻止死锁,一个线程在发现死锁用其他方法无法避免时, 必须释放已经占有的所有资源。示例3-3显示了这种方法。 Code Example 3-3 条件锁 Thread 1: Mutex_lock(&m1); Mutex_lock(&m2); Mutex_unlock(&m2); Mutex_unlock(&m1); Thread 2: For(;;){ Mutex_lock(&m2); If(mutex_trylock(&m1)==0) /*got it*/ break; /*didn't get it */ mutex_unlock(&m1); } mutex_unlock(&m1); mutex_unlock(&m2); 在上例中,线程1按照预定的顺序加锁,但线程2打乱了次序。为避免死锁,线程2必须小心操作互斥锁1:如果设置在等待互斥锁释放时阻塞,则可能导致死锁。 为保证上述情况不会发生,线程2调用mutex_trylock,如果互斥锁可用则用, 不可用则立刻返回失败。在这个例子当中,线程2一定要释放互斥锁2,以便线程1 可以使用互斥锁1和互斥锁2。 3.1.7锁内嵌于单链表当中 示例3-4同时占有3个锁,通过锁等级定义避免死锁。 Code Example 3-4 单链表结构 Typedef struct node1{ Int value; Struct node1 *link; ( 责任编辑:) 前一篇: 后一篇: 相关新闻(文章)
|
登录模块加载中...
热点操作系统技术
|
| 友情链接 | |