经过网上各种找,自己的各种尝试,终于搞清楚了设置线程锁属性的方法,以前用的mutex的attr都是采用的默认的,从来没有设置过,因为后续开发的需要,所以需要对其进行具体属性的设置,这里详细写一下这个设置的整个过程。
- 定义锁
pthread_mutex_t lock;
- 定义mutexattr_t变量
pthread_mutexattr_t attr;
- 设置mutexattr属性
pthread_mutexattr_init(&attr); // 初始化attr为默认属性
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); // 设置attr属性为PTHREAD_MUTEX_TIMED_NP,即默认属性(当一个线程加锁后,其余请求锁的线程形成等待队列,在解锁后按优先级获得锁)
- 其他相关属性
enum lock_type // 使用pthread_mutexattr_settype来更改
{
PTHREAD_MUTEX_TIMED_NP [default]//当一个线程加锁后,其余请求锁的线程形成等待队列,在解锁后按优先级获得锁。
PTHREAD_MUTEX_ADAPTIVE_NP // 动作最简单的锁类型,解锁后所有线程重新竞争。
PTHREAD_MUTEX_RECURSIVE_NP // 允许同一线程对同一锁成功获得多次。当然也要解锁多次。其余线程在解锁时重新竞争。
PTHREAD_MUTEX_ERRORCHECK_NP // 若同一线程请求同一锁,返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP动作相同。 此处特别注意linux和windows下的errno.h中的EDEADLK对应的宏的值有差别:linux下为35,windows下36
} type;
- linux下pthread.h中的线程属性
/* Mutex types. */
enum
{
PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_ADAPTIVE_NP
#ifdef __USE_UNIX98
,
PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
#endif
#ifdef __USE_GNU
/* For compatibility. */
, PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
#endif
};
- 互斥锁属性
互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。当前(glibc2.2.3,linuxthreads0.9)有四个值可供选择:
* PTHREAD_MUTEX_TIMED_NP,这是缺省值,也就是普通锁。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。
* PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
* PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个线程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。
* PTHREAD_MUTEX_ADAPTIVE_NP,适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
- lock相关函数描述
函数名
pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock - lock and unlock a mutex
概要
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
描述
pthread_mutex_lock() 函数锁住由mutex 指定的mutex 对象。如果mutex 已经被锁住,调用这个函数的线程阻塞直到mutex 可用为止。这跟函数返回的时候参数mutex 指定的mutex 对象变成锁住状态,同时该函数的调用线程成为该mutex 对象的拥有者。
如果mutex 对象的type 是 PTHREAD_MUTEX_NORMAL ,不进行deadlock detection( 死锁检测) 。企图进行relock 这个mutex 会导致deadlock. 如果一个线程对未加锁的或已经unlock 的mutex 对象进行unlock 操作,结果是不未知的。
如果mutex 类型是PTHREAD_MUTEX_ERRORCHECK ,那么将进行错误检查。如果一个线程企图对一个已经锁住的mutex 进行relock ,将返回一个错误。如果一个线程对未加锁的或已经unlock 的mutex 对象进行unlock 操作,将返回一个错误。
如果mutex 类型是PTHREAD_MUTEX_RECURSIVE ,mutex 会有一个锁住次数(lock count )的概念。当一个线程成功地第一次锁住一个mutex 的时候,锁住次数(lock count )被设置为1 ,每一次一个线程unlock 这个mutex 的时候,锁住次数(lock count )就减1 。当锁住次数(lock count )减少为0 的时候,其他线程就能获得该mutex 锁了。如果一个线程对未加锁的或已经unlock 的mutex 对象进行unlock 操作,将返回一个错误。
如果mutex 类型是PTHREAD_MUTEX_DEFAULT ,企图递归的获取这个mutex 的锁的结果是不确定的。unlock 一个不是被调用线程锁住的mutex 的结果也是不确定的。企图unlock 一个未被锁住的mutex 导致不确定的结果。
pthread_mutex_trylock() 调用在参数 mutex 指定的 mutex 对象当前被锁住的时候立即返回,除此之外, pthread_mutex_trylock() 跟 pthread_mutex_lock() 功能完全一样。
The pthread_mutex_unlock() 函数释放有参数 mutex 指定的 mutex 对象的锁。如果被释放取决于该 Mutex 对象的类型属性。如果有多个线程为了获得该 mutex 锁阻塞,调用 pthread_mutex_unlock() 将是该 mutex 可用,一定的调度策略将被用来决定哪个线程可以获得该 mutex 锁。(在 mutex 类型为 PTHREAD_MUTEX_RECURSIVE 的情况下,只有当 lock count 减为 0 并且调用线程在该 mutex 上已经没有锁的时候)(翻译到这里,才觉得我的这个锁概念是多么模糊)
如果一个线程在等待一个mutex 锁得时候收到了一个signal, 那么在从signal handler 返回的时候,该线程继续等待该mutex 锁,就像这个线程没有被中断一样。
返回值
成功, pthread_mutex_lock() 和 pthread_mutex_unlock() 返回0 ,否则返回一个错误的提示码
pthread_mutex_trylock() 在成功获得了一个mutex 的锁后返回0 ,否则返回一个错误提示码
错误
pthread_mutex_lock() 和 pthread_mutex_unlock() 失败的时候
-
[EINVAL]
mutex 在生成的时候,它的protocol 属性的值是PTHREAD_PRIO_PROTECT ,同时调用线程的优先级(priority) 比该mutex 的当前prority 上限高
pthread_mutex_trylock() 函数在一下情况会失败:
- The mutex could not be acquired because it was already locked.
-
[EBUSY]
mutex 已经被锁住的时候无法再获取锁
The pthread_mutex_lock(), pthread_mutex_trylock() and pthread_mutex_unlock() functions may fail if:
- mutex 指向的mutex 未被初始化 [EAGAIN]
- Mutex 的lock count( 锁数量) 已经超过 递归索的最大值,无法再获得该mutex 锁
-
[EINVAL]
pthread_mutex_lock() 函数在一下情况下会失败:
- 当前线程已经获得该mutex 锁
-
[EDEADLK]
pthread_mutex_unlock() 函数在以下情况下会失败:
- 当前线程不是该mutex 锁的拥有者
- 所有的这些函数的错误返回值都不会是[EINTR]
-
[EPERM]