线程的同步对象和线程一样也具有属性,上一节介绍了线程属性,本节将讨论线程的同步属性,包括互斥量属性、读写锁属性、条件变量属性和屏障属性。
对比线程属性,互斥量属性也有一组操作函数。
pthread_mutexattr_init 函数会用默认的互斥量属性初始化 pthread_mutexattr_t 结构,pthread_mutexattr_destroy 则用来反初始化。
值得注意的 3 个属性是:进程共享属性、健壮属性以及类型属性。POSIX.1 中,进程共享属性是可选的,可以通过检查是否定义了 _POSIX_THREAD_PROCESS_SHARED 符号或把 _SC_THREAD_PROCESS_SHARED 参数传给 sysconf 函数来判断平台是否支持该属性。
函数 pthread_mutexattr_getpshared 和 pthread_mutexattr_setpshared 可以用来查询和修改进程共享属性。在进程中,默认多个线程可以访问同一个同步对象,此时的进程共享互斥量属性需设置为 PTHREAD_PROCESS_PRIVATE。如果进程共享互斥量属性设置为 PTHREAD_PROCESS_SHARED,则从多个进程彼此之间共享的内存数据块中分配的互斥量就可以用于这些进程的同步。
函数 pthread_mutexattr_getrobust 和 pthread_mutexattr_setrobust 可分别用来获取和设置互斥量健壮属性的值。互斥量健壮属性与在多个进程间共享的互斥量有关。这意味着当持有互斥量的进程终止时,需要解决互斥量状态恢复的问题。这种情况发生时,互斥量处于锁定状态,恢复起来很困难,其它阻塞在这个锁的进程将会一直阻塞下去。
健壮属性取值有两种可能的情况,默认值是 PTHREAD_MUTEX_STALLED,这表示持有互斥量的进程终止时不需要采取特别的动作。这种情况下,使用互斥量后的行为是未定义的,等待该互斥量解锁的应用程序会被有效地“拖住”。另一个值是 PTHREAD_MUTEX_ROBUST,这个值将导致线程调用 pthread_mutex_lock 获取锁,而该锁被另一个进程持有,但它终止时并没有对其进行解锁,此时线程会阻塞,从 pthread_mutex_lock 返回的值为 EOWNERDEAD 而不是 0。应用程序可以通过该值获知,若有可能(要保护状态的细节以及如何进行恢复会因不同的应用程序而异),不管它们保护的互斥量状态如何,都需要进行恢复。
如果应用状态无法恢复,在线程对互斥量解锁以后,该互斥量将处于永久不可用状态。为避免这样的问题,线程就可以调用 pthread_mutex_consistent 函数来指明与该互斥量相关的状态在互斥量解锁之前是一样的。如果线程没有先调用该函数就对互斥量进行了解锁,那么其他试图获取该互斥量的阻塞线程就会得到错误码 ENOTRECOVERABLE。若发生这种情况,互斥量将不再可用。线程通过提前调用该函数,就能让互斥量正常工作,这样它就可以持续被使用。
pthread_mutexattr_gettype 和 pthread_mutexattr_settype 函数可以获取和修改互斥量类型属性。类型互斥量属性控制着互斥量的锁定特性。POSIX.1 定义了 4 种类型。
1、PTHREAD_MUTEX_NORMAL:标准互斥量类型,不做任何特殊的错误检查或死锁检测。
2、PTHREAD_MUTEX_ERRORCHECK:此互斥量类型提供错误检查。
3、PTHREAD_MUTEX_RECURSIVE:此互斥量类型允许同一线程在互斥量解锁之前对互斥量进行多次加锁。递归互斥量维护锁的计数,在解锁次数和加锁次数不相同时不会释放锁。
4、PTHREAD_MUTEX_DEFAULT:此互斥量类型可以提供默认特性和行为。操作系统在实现它的时候可以把这种类型自由地映射到其他互斥量类型中的一种。
这 4 种类型的行为如下表所示。其中,“不占用时解锁”这一栏指的是,一个线程对被另一个线程加锁的互斥量进行解锁的情况;“在已解锁时解锁”指的是,一个线程对已经解锁的互斥量进行解锁的情况。
[img]http://dl2.iteye.com/upload/attachment/0127/8532/28c982dc-a24f-3e7f-85b4-c4fcc1882dbb.png[/img]
介绍了互斥量属性后,其他同步属性就好理解了,它们也支持一组类似的函数,可对比互斥量属性进行理解。
对于读写锁,它支持的唯一属性是进程共享属性,所以它有这样几个函数。
条件变量支持进程共享属性和时钟属性。前者控制着条件变量是可以被单进程的多个线程使用,还是可以被多进程的线程使用;后者则控制计算 pthread_cond_timedwait 函数的超时参数时采用的是哪个时钟。pthread_condattr_getclock 和 pthread_condattr_setclock 函数可以用来获取和修改用于 pthread_cond_timedwait 的时钟 ID。
屏障也只支持进程共享属性,它控制着屏障是可以被多进程的线程使用,还是只能被初始化屏障的进程内的多线程使用。它有这样一组函数。
对比线程属性,互斥量属性也有一组操作函数。
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,
int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
int pthread_mutexattr_getrobust(const pthread mutexattr_t *restrict attr,
int *restrict robust);
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robust);
int pthread_mutex_consistent(pthread_mutex_t *mutex);
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
/* 所有函数的返回值:若成功,返回 0;否则,返回错误编号 */
pthread_mutexattr_init 函数会用默认的互斥量属性初始化 pthread_mutexattr_t 结构,pthread_mutexattr_destroy 则用来反初始化。
值得注意的 3 个属性是:进程共享属性、健壮属性以及类型属性。POSIX.1 中,进程共享属性是可选的,可以通过检查是否定义了 _POSIX_THREAD_PROCESS_SHARED 符号或把 _SC_THREAD_PROCESS_SHARED 参数传给 sysconf 函数来判断平台是否支持该属性。
函数 pthread_mutexattr_getpshared 和 pthread_mutexattr_setpshared 可以用来查询和修改进程共享属性。在进程中,默认多个线程可以访问同一个同步对象,此时的进程共享互斥量属性需设置为 PTHREAD_PROCESS_PRIVATE。如果进程共享互斥量属性设置为 PTHREAD_PROCESS_SHARED,则从多个进程彼此之间共享的内存数据块中分配的互斥量就可以用于这些进程的同步。
函数 pthread_mutexattr_getrobust 和 pthread_mutexattr_setrobust 可分别用来获取和设置互斥量健壮属性的值。互斥量健壮属性与在多个进程间共享的互斥量有关。这意味着当持有互斥量的进程终止时,需要解决互斥量状态恢复的问题。这种情况发生时,互斥量处于锁定状态,恢复起来很困难,其它阻塞在这个锁的进程将会一直阻塞下去。
健壮属性取值有两种可能的情况,默认值是 PTHREAD_MUTEX_STALLED,这表示持有互斥量的进程终止时不需要采取特别的动作。这种情况下,使用互斥量后的行为是未定义的,等待该互斥量解锁的应用程序会被有效地“拖住”。另一个值是 PTHREAD_MUTEX_ROBUST,这个值将导致线程调用 pthread_mutex_lock 获取锁,而该锁被另一个进程持有,但它终止时并没有对其进行解锁,此时线程会阻塞,从 pthread_mutex_lock 返回的值为 EOWNERDEAD 而不是 0。应用程序可以通过该值获知,若有可能(要保护状态的细节以及如何进行恢复会因不同的应用程序而异),不管它们保护的互斥量状态如何,都需要进行恢复。
如果应用状态无法恢复,在线程对互斥量解锁以后,该互斥量将处于永久不可用状态。为避免这样的问题,线程就可以调用 pthread_mutex_consistent 函数来指明与该互斥量相关的状态在互斥量解锁之前是一样的。如果线程没有先调用该函数就对互斥量进行了解锁,那么其他试图获取该互斥量的阻塞线程就会得到错误码 ENOTRECOVERABLE。若发生这种情况,互斥量将不再可用。线程通过提前调用该函数,就能让互斥量正常工作,这样它就可以持续被使用。
pthread_mutexattr_gettype 和 pthread_mutexattr_settype 函数可以获取和修改互斥量类型属性。类型互斥量属性控制着互斥量的锁定特性。POSIX.1 定义了 4 种类型。
1、PTHREAD_MUTEX_NORMAL:标准互斥量类型,不做任何特殊的错误检查或死锁检测。
2、PTHREAD_MUTEX_ERRORCHECK:此互斥量类型提供错误检查。
3、PTHREAD_MUTEX_RECURSIVE:此互斥量类型允许同一线程在互斥量解锁之前对互斥量进行多次加锁。递归互斥量维护锁的计数,在解锁次数和加锁次数不相同时不会释放锁。
4、PTHREAD_MUTEX_DEFAULT:此互斥量类型可以提供默认特性和行为。操作系统在实现它的时候可以把这种类型自由地映射到其他互斥量类型中的一种。
这 4 种类型的行为如下表所示。其中,“不占用时解锁”这一栏指的是,一个线程对被另一个线程加锁的互斥量进行解锁的情况;“在已解锁时解锁”指的是,一个线程对已经解锁的互斥量进行解锁的情况。
[img]http://dl2.iteye.com/upload/attachment/0127/8532/28c982dc-a24f-3e7f-85b4-c4fcc1882dbb.png[/img]
介绍了互斥量属性后,其他同步属性就好理解了,它们也支持一组类似的函数,可对比互斥量属性进行理解。
对于读写锁,它支持的唯一属性是进程共享属性,所以它有这样几个函数。
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr,
int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
/* 所有函数的返回值:若成功,返回 0;否则,返回错误编号 */
条件变量支持进程共享属性和时钟属性。前者控制着条件变量是可以被单进程的多个线程使用,还是可以被多进程的线程使用;后者则控制计算 pthread_cond_timedwait 函数的超时参数时采用的是哪个时钟。pthread_condattr_getclock 和 pthread_condattr_setclock 函数可以用来获取和修改用于 pthread_cond_timedwait 的时钟 ID。
#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr,
int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);
int pthread_condattr_getclock(const pthread_condattr_t *restrict attr,
clockid_t *restrict clock_id);
int pshared_condattr_setclock(pshared_condattr_t *attr, clockid_t clock_id);
/* 所有函数的返回值:若成功,返回 0;否则,返回错误编号 */
屏障也只支持进程共享属性,它控制着屏障是可以被多进程的线程使用,还是只能被初始化屏障的进程内的多线程使用。它有这样一组函数。
#include <pthread.h>
int pthread_barrierattr_init(pthread_barrierattr_t *attr);
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *restrict attr,
int *restrict pshared);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared);
/* 所有函数的返回值:若成功,返回 0;否则,返回错误编号 */