互斥量也称为“互斥锁”,是用来保护共享数据块(临界区)的一种数据结构。其英文名称:mutex,是MUTual EXclusion的缩写。
互斥量有两种状态:未锁定(unlocked)和已锁定(locked)。“未锁定”是指互斥量没有被任何线程拥有,“已锁定”是指互斥量被某个线程拥有。互斥量永远不会被两个(或多个)不同的线程同时拥有。当线程试图去锁定一个已经被其它线程拥有的互斥量时,它会被挂起(或称为阻塞),直到拥有互斥量的线程释放该互斥量。对于递归型互斥量或者错误检查型互斥量,其行为详见下文。

POSIX下互斥量的数据类型称为pthread_mutex_t,与互斥量相关的函数如下:
#include <pthread.h>
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//普通互斥量
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;//递归互斥量
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;//错误检查互斥量
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
返回值:pthread_mutex_init() 总是返回0,其它函数成功时返回0,失败时返回非零值的错误代码。
1、互斥量的初始化
互斥量可以通过函数pthread_mutex_init()初始化,或者静态初始化。
函数:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
参数:
①mutex:指向互斥量结构体变量的指针;
②mutexattr:指向互斥量属性变量的指针;
互斥量的属性:初始化时可以指定互斥量的属性,不同的属性在试图对一个已经被锁定的互斥锁加锁时表现不同。
有四种属性:
①PTHREAD_MUTEX_TIMED_NP:默认值,也就是普通互斥量。当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁。这种锁策略保证了资源分配的公平性。当参数为NULL时,使用该属性。
②PTHREAD_MUTEX_RECURSIVE_NP:递归互斥量。允许同一个线程对同一个互斥量成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁时重新竞争。
③PTHREAD_MUTEX_ERRORCHECK_NP:检错互斥量。如果同一个线程请求同一个互斥量,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样保证当不允许多次加锁时不出现最简单情况下的死锁。
④PTHREAD_MUTEX_ADAPTIVE_NP:自适应互斥量。动作最简单的锁类型,仅等待解锁后重新竞争。
返回值:永远为0
互斥量也可以被静态初始化,常量:
①PTHREAD_MUTEX_INITIALIZER:用于普通互斥量,快速初始化;
②PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP:用于递归互斥量;
③PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP:用于错误检查互斥量;
例如:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
2、加锁(锁定互斥量)
函数pthread_mutex_lock()用于锁定互斥量,也称为对互斥量“加锁”。
函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:指向mutex互斥量的指针
返回值:成功时返回0,失败时返回非零值的错误代码,包括:
①EINVAL :互斥量没有被正确初始化;
②EDEADLK:互斥量已被锁定(仅用于错误检查型互斥量)
若没有被其它线程拥有,则加锁成功后立即返回。
若互斥量已经被其它线程拥有,其行为取决于互斥量的类型。
对于普通互斥量,调用线程会阻塞直到互斥量可用。
如果是“错误检查型”互斥量,pthread_mutex_lock()会立即返回错误码EDEADLK。
如果是“递归型”互斥量,pthread_mutex_lock()会成功并立即返回,同时记录调用线程锁定互斥锁的次数。
在互斥锁返回到未锁定状态之前,必须执行相同次数的pthread_mutex_unlock()操作。
3、尝试加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
参数:指向mutex互斥量的指针
返回值:成功时返回0,失败时返回非零值的错误代码,包括:
①EBUSY :无法拥有互斥量因为它已经被锁定;
②EINVAL:互斥量没有被正确初始化;
pthread_mutex_trylock()的行为与pthread_mutex_lock()相同,唯一的区别是:当互斥量被所锁定时,该函数立即返回错误码:EBUSY。
4、解锁(释放互斥量)
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功时返回0,失败时返回非零值的错误代码,包括:
①EINVAL:互斥量没有被正确初始化;
②EPERM:调用线程没有拥有该互斥量;
5、销毁互斥量
当互斥量不再使用时,可以对其进行销毁。
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:指向mutex互斥量的指针
返回值:成功时返回0,失败时返回非零值的错误代码,包括:
①EBUSY:该互斥量当前已被锁定。
销毁互斥量会清理其内部状态。不要在互斥量仍被锁定时调用pthread_mutex_destroy(),否则行为未定义。销毁后的互斥量不能再用于加锁/解锁,除非重新初始化。该函数并不能释放互斥量占用的内存资源,对于动态分配内存(malloc)的互斥量,仍需使用free()函数释放其内存。
北岛夜话



发表评论