首页 理论教育 互斥锁的特性及使用方法

互斥锁的特性及使用方法

时间:2023-10-31 理论教育 版权反馈
【摘要】:互斥锁通过锁机制来实现线程间的同步。互斥锁具有以下3个特性。表10-2 互斥锁函数1.初始化在Linux下,线程的互斥锁在使用前要对它进行初始化。表10-3 互斥锁的属性及意义2.互斥操作初始化后就可以对互斥锁进行加锁了。图10-3 互斥锁操作结果在该例中,主线程占用互斥锁后,子线程试图占用同一把互斥锁时会被阻塞,直到主线程unlock这把锁。

互斥锁的特性及使用方法

互斥锁通过锁机制来实现线程间的同步。互斥锁从本质上说就是一把锁,提供对共享资源的保护访问。互斥锁具有以下3个特性。

原子性:如果一个线程锁定了一个互斥量,那么临界区内的操作要么全部完成,要么一个也不执行。

唯一性:如果一个线程锁定了一个互斥量,那么在它解除锁定之前,没有其他线程可以锁定这个互斥量。

非繁忙等待:如果一个线程已经锁定了一个互斥量,第2个线程又试图去锁定这个互斥量,则第2个线程将被挂起(不占用任何CPU资源),直到第1个线程解除对这个互斥量的锁定为止。第2个线程被唤醒并继续执行,同时锁定这个互斥量。

表10-2列出了操作互斥锁的几个互斥锁函数,这些函数都声明在头文件pthread.h中。

表10-2 互斥锁函数

978-7-111-33316-6-Chapter10-30.jpg

1.初始化

在Linux下,线程的互斥锁在使用前要对它进行初始化。对于静态分配的互斥锁,可以把它设置为PTHREAD_MUTEX_INITIALIZER,或者调用pthread_mutex_init()。操作语句如下:

978-7-111-33316-6-Chapter10-31.jpg

对于动态分配的互斥量,在申请内存(malloc)之后,通过pthread_mutex_init()进行初始化,并且在释放内存(free)前需要调用pthread_mutex_destroy()来注销互斥锁。操作语句如下:

978-7-111-33316-6-Chapter10-32.jpg

返回值:若成功,则返回0;若出错,则返回错误编号。

以上函数中的参数mutexattr表示互斥锁的属性。互斥锁的属性及意义见表10-3。如果使用默认的属性初始化互斥量,只需把attr设为NULL即可。

表10-3 互斥锁的属性及意义

978-7-111-33316-6-Chapter10-33.jpg

2.互斥操作

初始化后就可以对互斥锁进行加锁了。如果互斥锁已经上了锁,调用线程会阻塞,直到被解锁。首先介绍加锁函数,该函数的原型如下:

978-7-111-33316-6-Chapter10-34.jpg(www.xing528.com)

●返回值:若成功,则返回0;若出错,则返回错误编号。

其中,pthread_mutex_trylock()函数是非阻塞调用模式。如果互斥锁没被锁住,pthread_mutex_trylock()函数将进行加锁,并获得对共享资源的访问权限;如果互斥锁被锁住了,pthread_mutex_trylock()函数将不会阻塞等待而直接返回忙状态。

解锁函数pthread_mutex_unlock()的原型为

978-7-111-33316-6-Chapter10-35.jpg

●返回值:若成功,则返回0;若出错,则返回错误编号。

3.死锁

死锁主要发生在有多个依赖锁存在时,会在一个线程试图以与另一个线程相反顺序锁住互斥锁时发生。死锁是使用互斥锁时应该尽量避免的,pthread库可以跟踪这种情形,最后一个线程试图调用pthread_mutex_lock()时会失败,并返回类型为EDEADLK的错误。

【例10-3】互斥锁。

本例使用函数pthread_mutex_unlock()和pthread_mutex_lock()来实现互斥锁。

设计步骤

1)在Vim中创建一个新工程文件,命名为“example10_3.c”。

2)在“example10_3.c”中创建的代码如下所示。

978-7-111-33316-6-Chapter10-36.jpg

978-7-111-33316-6-Chapter10-37.jpg

3)使用GCC编译并运行程序,结果如图10-3所示。

978-7-111-33316-6-Chapter10-38.jpg

图10-3 互斥锁操作结果

在该例中,主线程占用互斥锁后,子线程试图占用同一把互斥锁时会被阻塞,直到主线程unlock这把锁。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈