北岛夜话
原创工业智能控制领域(PLC、单片机/嵌入式、机器人、通信、机器视觉)的技术及经验分享。
文章572 浏览9931494

线程同步(1)——互斥量

互斥量也称为“互斥锁”,是用来保护共享数据块(临界区)的一种数据结构。其英文名称:mutex,是MUTual EXclusion的缩写。

互斥量有两种状态:未锁定(unlocked)和已锁定(locked)。“未锁定”是指互斥量没有被任何线程拥有,“已锁定”是指互斥量被某个线程拥有。互斥量永远不会被两个(或多个)不同的线程同时拥有。当线程试图去锁定一个已经被其它线程拥有的互斥量时,它会被挂起(或称为阻塞),直到拥有互斥量的线程释放该互斥量。对于递归型互斥量或者错误检查型互斥量,其行为详见下文。

cover.png

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()函数释放其内存。


取消

感谢您的支持,欢迎常来看看!

扫码支持
一点动力,多少随意

打开支付宝扫一扫,即可进行扫码打赏哦

最后编辑于:2026/08/12作者: 北岛李工

发表评论

恭祝各位朋友在丙午马年新春快乐,工作顺利,阖家安康!

×