互斥量属性
互斥量属性是用pthread_mutexattr_t结构表示的。和线程属性是很类似的。
初始化和反初始化
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t*attr);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
值得注意的属性
- 进程共享属性:确定是否进程间可以共享该互斥量
- 健壮属性
- 类型属性
1. 共享属性
#include <pthread.h>
int pthread_mutexattr_getpshared(const pthread_mutexattr_t*restrict attr,int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutex-attr_t *attr,int pshared);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
进程共享互斥量属性设置为PTHREAD_PROCESS_PRIVATE时,允许pthread线程库提供更有效的互斥量实现,这在多线程应用程序中是默认的情况。在多个进程共享多个互斥量的情况下, pthread线程库可以限制开销较大的互斥量实现。 互斥量健壮属性与在多个进程间共享的互斥量有关。这意味着,当持有互斥量的进程终止时,需要解决互斥量状态恢复的问题。这种情况发生时,互斥量处于锁定状态,恢复起来很困难。其他阻塞在这个锁的进程将会一直阻塞下去。
2. 健壮属性
#include <pthread.h>
int pthread_mutexattr_getrobust(const pthread_mutexattr_t*restrict attr,int *restrict robust);
int pthread_mutexattr_setrobust(pthread_mutex-attr_t *attr,int robust);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
健壮属性取值有两种可能的情况。 1. 默认值是 PTHREAD_MUTEX_STALLED,这意味着持有互斥量的进程终止时不需要采取特别的动作。这种情况下,使用互斥量后的行为是未定义的,等待该互斥量解锁的应用程序会被有效地“拖住”。 2. 另一个取值是PTHREAD_MUTEX_ROBUST。这个值将导致线程调用pthread_mutex_lock获取锁,而该锁被另一个进程持有,但它终止时并没有对该锁进行解锁,此时线程会阻塞,从pthread_mutex_lock返回的值为EOWNERDEAD而不是0。应用程序可以通过这个特殊的返回值获知,若有可能(要保护状态的细节以及如何进行恢复会因不同的应用程序而异),不管它们保护的互斥量状态如何,都需要进行恢复。
使用健壮的互斥量改变了我们使用pthread_mutex_lock的方式,因为现在必须检查3个返回值而不是之前的两个:不需要恢复的成功、需要恢复的成功以及失败。但是,即使不用健壮的互斥量,也可以只检查成功或者失败。
3. 类型属性
POSIX.1定义了4中类型: + PTHREAD_MUTEX_NORMAL:一种标准互斥量类型,不做任何特殊的错误检查或死锁检测。. + PTHREAD_MUTEX_ERRORCHECK:此互斥量类型提供错误检查。 + PTHREAD_MUTEX_RECURSIVE:此互斥量类型允许同一线程在互斥量解锁之前对该互斥量进行多次加锁。递归互斥量维护锁的计数,在解锁次数和加锁次数不相同的情况下,不会释放锁。所以,如果对一个递归互斥量加锁两次,然后解锁一次,那么这个互斥量将依然处于加锁状态,对它再次解锁以前不能释放该锁。 + PTHREAD_MUTEX_DEFAULT:此互斥量类型可以提供默认特性和行为。操作系统在实现它的时候可以把这种类型自由地映射到其他互斥量类型中的一种。例如,Linux3.2.0把这种类型映射为普通的互斥量类型,而FreeBSD 8.0则把它映射为错误检查互斥量类型。
总结如下图: ![IMAGE](resources/237608CE7737956B76CBB8EBCCB0132D.jpg =1083x201) “不占用时解锁”这一栏指的是,一个线程对被另一个线程加锁的互斥量进行解锁的情况。“在已解锁时解锁”这一栏指的是,当一个线程对已经解锁的互斥量进行解锁时将会发生什么,这通常是编码错误引起的。
得到和修改互斥量类型属性:
#include <pthread.h>
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_rwlockattr_init 初始化pthread_rwlockattr_t结构,用pthread_rwlockattr_destroy反初始化该结构。
#include <pthread.h>
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t*attr);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
读写锁支持的唯一属性是进程共享属性。它与互斥量的进程共享属性是相同的。就像互斥量的进程共享属性一样,有一对函数用于读取和设置读写锁的进程共享属性。
#include <pthread.h>
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *restrict attr,int *restrict pshared);
int pthread_rwlockattr_setpshared(pthread_rwlock-attr_t *attr,int pshared);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
虽然POSIX只定义了一个读写锁属性,但不同平台的实现可以自由地定义额外的、非标准的属性。
条件标量属性
Single UNIX Specification目前定义了条件变量的两个属性:进程共享属性和时钟属性。与其他的属性对象一样,有一对函数用于初始化和反初始化条件变量属性。
#include <pthread.h>
int pthread_condattr_init(pthread_condattr_t *attr);
int pthread_condattr_destroy(pthread_condattr_t *attr);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
与其他的同步属性一样,条件变量支持进程共享属性。它控制着条件变量是可以被单进程的多个线程使用,还是可以被多进程的线程使用。要获取进程共享属性的当前值,可以用pthread_condattr_getpshared函数。设置该值可以用pthread_condattr_setpshared函数。
#include <pthread.h>
int pthread_condattr_getpshared(const pthread_condattr_t *restrict attr, int *restrict pshared);
int pthread_condattr_setpshared(pthread_condattr_t*attr,int pshared);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
时钟属性控制计算pthread_cond_timedwait函数的超时参数(tsptr)时采用的是哪个时钟。合法值取自图 6-8 中列出的时钟 ID。可以使用 pthread_condattr_getclock 函数获取可被用于pthread_cond_timedwait 函数的时钟 ID,在使用pthread_cond_timedwait 函数前需要用pthread_condattr_t对象对条件变量进行初始化。可以用pthread_condattr_setclock函数对时钟ID进行修改。
#include <pthread.h>
int pthread_condattr_getclock(const pthread_condattr_t *restrict attr, clockid_t *restrict clock_id);
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id);
//两个函数的返回值:若成功,返回0;否则,返回错误编号
奇怪的是,Single UNIX Specification并没有为其他有超时等待函数的属性对象定义时钟属性。