pthread_mutex_t互斥量
admin
2024-04-04 04:48:36
0次

静态分配的互斥量

互斥量既可以像静态变量那样分配,也可以在运行时动态创建(例如,通过malloc()在一块内存中分配)。这里先介绍静态分配,随后介绍动态分配。

互斥量是属于pthrad_mutex_t类型的变量。在使用之前必须对其初始化。对于静态分配的互斥量而言,可如下所示,将PTHREAD_MUTEX_INITIALIZER赋给变量:

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

加锁和解锁互斥量

初始化之后,互斥量处于未锁定状态。函数pthread_mutex_lock()可以锁定某一互斥量,而函数pthread_mutex_unlock()则可以将一个互斥量解锁。

#include 
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);Both return 0 on success, or a positive error number on error.
pthread_mutex_lock()
  • 如果互斥量当前处于未锁定状态, pthread_mutex_lock()将锁定互斥量并立即返回。
  • 如果其他线程已经锁定了这一互斥量,那么pthread_lock()会一直阻塞,直至该互斥量被解锁,调用将锁定该互斥量并返回。
  • 如果发起pthread_mutex_lock()调用的线程自身之前已然将目标互斥量锁定,对于互斥量的默认类型而言,可能会产生两种后果——视具体实现而定:线程陷入死锁(deadlock),因为试图锁定已为自己所持有的互斥量而遭到阻塞;或者调用失败,返回EDEADLK 错误。在Linux上,默认情况下线程会发生死锁。
pthread_mutex_unlock()

pthread_mutex_unlock()将解锁之前已遭调用线程锁定的互斥量,以下行为均属错误:

  • 对处于未锁定状态的互斥量进行解锁。
  • 解锁由其他线程锁定的互斥量。

如果有不止一个线程在等待获取由函数pthread_mutex_unlock()解锁的互斥量,则无法判断究竟哪个线程如愿以偿。

pthread_mutex_trylock()和pthread_mutex_timedlock()

Pthread API提供了pthread_mutex_lock()函数的两个变体:ptrhead_mutex_trylock()和ptrhead_mutex_timelock()。

  • 如果信号量已然锁定,对其执行函数pthread_mutex_trylock()会失败并返回EBUSY错误,除此之外,该函数与pthread_mutex_lock()行为相同。
  • 除了调用者可以指定一个附加参数abstime(设置线程等待获取互斥量时休眠的时间限制)外,pthread_mutex_timedlock()与pthread_mutex_lock()没有差别。如果参数abstime指定的时间间隔期满,而调用线程又没有获得对互斥量的拥有权,那么函数pthread_mutex_timedlock()返回ETIMEDOUT错误。

函数pthread_mutex_trylock()和pthread_mutex_timedlock()比pthread_mutex_lock()的使用频率要低很多。在大多数经过良好设计的应用程序中,线程对互斥量的持有时间应尽可能短,以避免妨碍其他线程的并发执行。这也保证了遭阻塞的其他线程可以很快获取对互斥量的锁定,若某一线程使用pthread_mutex_trylock()周期性地轮询是否可以对互斥量加锁,则有可能要承担这样的风险:当队列中的其他线程通过调用pthread_mutex_lock()相继获得对互斥量的访问时,该线程将始终与此互斥量无缘。

动态初始化互斥量

静态初始值PTHREAD_MUTEX_INITIALIZER,只能用于对如下互斥量进行初始化:经由静态分配且携带默认属性。
其他情况下,必须调用pthread_mutex_init()对互斥量进行动态初始化。

#include 
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);Returns 0 on success, or a positive error number on error.
  • 参数mutex
    • 指定函数执行初始化操作的目标互斥量。
  • 参数attr
    • 是指向pthread_mutexattr_t类型对象的指针,该对象在函数调用之前已经过了初始化处理,用于定义互斥量的属性。
    • 若将attr设为NULL,则该互斥量的各种属性会取默认值。

SUSv3规定,初始化一个业已初始化的互斥量将导致未定义的行为,应当避免这一行为。
以下情况必须使用pthread_mutex_init()而非静态初始化互斥量。

  • 动态分配于堆中的互斥量。
    • 例如,动态创建针对某一结构的链表,表中每个结构都包含一个pthread_mutex_t类型的字段来存放互斥量,借以保护对该结构的访问。
  • 互斥量是在栈中分配的自动变量。
  • 初始化经由静态分配,且不使用默认属性的互斥量。

(也即是,只有静态分配且使用默认属性的互斥量才用静态初始化。)

当不再需要经由自动或动态分配的互斥量时,应使用pthread_mutex_destroy()将其销毁。(对于使用PHREAD_MUTEX_INTIALIZER 静态初始化的互斥量,无需调用pthread_mutex_destroy()。)

#include 
int pthread_mutex_destroy(pthread_mutex_t * mutex);Returns 0 on success, or a positive error number on error.

只有互斥量处于未锁定状态,且后续也无任何线程企图锁定它时,将其销毁才是安全的。
若互斥量驻留于动态分配的一片内存区域中,应在释放(free)此内存区域前将其销毁。对于自动分配的互斥量,也应在宿主函数返回前将其销毁。

经由pthread_mutex_destroy()销毁的互斥量,可调用pthread_mutex_init()对其重新初始化。

互斥量类型

前面的规则归纳如下:

  • 同一线程不应对同一互斥量加锁两次。
  • 线程不应对不为自己所拥有的互斥量解锁(亦即,尚未锁定互斥量)。
  • 线程不应对一尚未锁定的互斥量做解锁动作。

准确地说,上述情况的结果取决于互斥量类型(type),SUSv3定义了以下互斥量类型:

  • PTHREAD_MUTEX_NORMAL
    • 该类型的互斥量不具有死锁检测(自检)功能。
    • 如线程试图对已由自己锁定的互斥量加锁,则发生死锁。
    • 互斥量处于未锁定状态,或者已由其他线程锁定,对其解锁会导致不确定的结果。(在Linux上,对这类互斥量的上述两种操作都会成功。)
  • PTHREAD_MUTEX_ERRORCHECK
    • 对此类互斥量的所有操作都会执行错误检查。所有上述3种情况都会导致相关Pthreads函数返回错误。
    • 这类互斥量运行起来比一般类型要慢,不过可以将其作为调试工具,以发现程序哪里违反了互斥量使用的基本原则。
  • PTHREAD_MUTEX_RECURSIVE
    • 递归互斥量有一个锁计数器。
    • 当线程第一次取得互斥量时,会将锁计数器都置1.
    • 后续由同一线程执行的每次加锁操作会递增锁计数器的数值,而解锁操作则递减计数器计数。
    • 只有当锁计数器值降至0时,才会释放(release,亦即可谓其他线程所用)该互斥量。
    • 解锁时如目标互斥量处于未锁定状态,或是已由其他线程锁定,操作都会失败。

Linux的线程实现针对以上各种类型的互斥量提供了非标准的静态初始值(例如,PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP),以便对那些通过静态分配的互斥量进行初始化,而无需使用pthread_mutex_init()函数。不过,为保证程序可移植性,应该避免使用这些初始值。

除了上述类型,SUSv3还定义了PTHREAD_MUTEX_DEFAULT类型:

  • 使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量,或是经调用参数 attr为NULL的pthread_mutex_init()函数所创建的互斥量,都属于此类型。
  • Linux上,PTHREAD_MUTEX_DEFAULT类型互斥量的行为与PTHREAD_MUTEX_NORMAL类型相仿。

下例创建一个带有错误检查属性的互斥量:

pthread_mutex_t mtx;
pthread_mutexattr_t mtxAttr;
pthread_mutexattr_init(&mtxAttr);
pthread_mutexattr_settype(&mtxAttr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(mtx, &mtxAttr);
pthread_mutexattr_destroy(&mtxAttr);

相关内容

热门资讯

AI做攻略、“双向奔赴”……国... 本文转自:人民网人民网记者 许维娜今年国庆假期,AI(人工智能)成了不少年轻人的“旅行搭子”。行前做...
合肥的这个“梗”, 翻篇了 社交平台的评论区,曾长期流传一句专属于合肥的黑色幽默。有人问合肥哪里好玩,本地网友半开玩笑地回复:合...
7万+旅游中高层都在的群,今天... 做旅游这行,资源卡位、渠道互通、项目落地——往往就差一个“对的机会”。我们的行业社群已聚集70,00...
一场帐篷音乐节,如何让井研从“... 帐篷音乐节现场封面新闻记者 周洪攀10月的研溪湿地,晚风里裹着柑橘的清甜与民谣的回响。夜幕降临,10...
白鹤翩翩落星愿,上海迪士尼度假... 10月9日,世界候鸟日前夕,上海迪士尼度假区星愿公园的湖风里多了一分白鹤的灵动。三座白鹤雕塑正式揭幕...
成都锦江边赏初秋枫叶飘飘 目前,成都锦江边国华街枫叶树红了。近年来,国华街附近的几条街都栽种了红枫树,是城区较集中看枫叶的点位...
GBTA:商务旅行正在复苏,但... 亚太正在成为全球商务旅行增长的重要引擎。在经历疫情后的快速反弹之后,全球商务旅行正在进入一个新的增长...
从景区焕新到节赛引流 邹城双节... 齐鲁网·闪电新闻10月9日讯 中秋、国庆“双节”假期,邹城市文化和旅游局提前谋划、周密部署,立足自身...
江山如此多娇 且看石楼今朝 金秋十月,黄河岸畔秋意盎然,丰收盛会喜迎国庆。本次石楼国庆文旅活动以“江山如此多娇,且看石楼今朝”为...
海南国庆假期接待游客475.4... 2026年国庆假期,海南接待游客475.40万人次,较2025年增长13.1%,较2024年增长15...