- 专栏内容:linux下并发编程
- 个人主页:我的主页
- 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.
目录
前言
概述
原理
初始化
进程和线程使用的不同点
死锁
接口
基本API
属性设置
带等待超时的接口
代码演示
结尾
前言
本专栏主要分享linux下并发编程相关知识,包括多进程,多线程,进程/线程间通信,并发同步控制,以及高并发下性能提升,请大家多多留言。
概述
本文主要介绍并发编程中的互斥量,linux中提供了一系列pthread_mutex打头的接口完成互斥量的功能。它不同于信号量,在并发编程中应用非常广泛。
原理
互斥量,顾名思义,就是相互排斥,也就是说两个并发任务想要达到顺序排列执行目的时,就要用到互斥量。在关键代码包在互斥量的lock/unlock中间,那么这段代码在多个任务并发时也是顺次执行的,但是它们的顺序是竞争的结果,看谁也争抢到互斥量并加锁。
初始化
有两种形式,一种是静态初始化,使用默认的值,如下;
pthead_mutex_t muetx = PTHREAD_MUTEX_INITIALIZER;
一种是调用初始化API, pthread_mutex_init,这就比较灵活,可以对mutex的属性进行设置。
进程和线程使用的不同点
默认是PTHREAD_PROCESS_PRIVATE 在多线程间的使用,也是就进程内部,进程间的使用PTHREAD_PROCESS_SHARED,同时pthread_mutex_t变量也需要在共享内存中,这样状态的变化在多进程中都可以访问到。
死锁
在互斥量使用的过程中我们要避免死锁的发生,如果有多种锁的使用时,还需要增加死锁检测机制,而不仅仅是靠代码保证。
几种防止策略,一是尽量使用单一的互斥量锁;二是互斥量锁间避免嵌套使用;三是嵌套使用时,按一定次序进行加锁,避免无序加锁;四是使用带有超时的加锁方法,在超时时释放持有的其它锁;
接口
基本API
头文件
#include <pthread.h>
/*创建并初始化,以及销毁*/
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
/* 加锁,尝试加锁,解锁 */
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
属性设置
头文件
#include <pthread.h>
/* mutex attribute创建初始化,以及销毁 */
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy( pthread_mutexattr_t *attr );
(1)共享属性
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
int *pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
int pshared);
设置属性取值为:
PTHREAD_PROCESS_PRIVATE,mutex在单进程的线程间共享使用。这是默认取值。
PTHREAD_PROCESS_SHARED,mutex可以在任意线程间使用,只要可以访问到mutex的线程,也就是在多进程间也可以使用。
(2)健壮(robust)属性
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr,
int *robustness);
int pthread_mutexattr_setrobust(const pthread_mutexattr_t *attr,
int robustness);
设置属性值为:
PTHREAD_MUTEX_STALLED,当持有lock的线程在中止前没有调用unlock,那么其它等待该mutex的线程将不能获取到,一直会被阻塞。这是默认值。
PTHREAD_MUTEX_ROBUST,当持有lock的线程在中止前没有调用unlock,那么其它等待者可以获得,在下一个获得mutex的线程,得到的返回码为EOWNERDEAD,此时需要调用pthread_mutex_consistent,让mutex的状态进行同步,否则不能进行其它操作。
(3)类型属性
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
类型属性,主要对于重复lock,还有重复unlock的行为,在不同类型下,以及与健壮属性的结合时,有不同的表现,具体解释如下:
PTHREAD_MUTEX_NORMAL ,不会检测重复加锁产生的死锁,对于没加锁时调用unlock或重复unlock由健壮属性决定;
PTHREAD_MUTEX_ERRORCHECK ,检测死锁和没持用锁时的unlock行为,都返回错误码;
PTHREAD_MUTEX_RECURSIVE ,当前线程重复lock时,会成功,mutex只是增加count值,当然unlock的次数也需要对应,只有count为零时才能真正释放锁。在调用pthread_mutex_trylock时,会对count值递增;其它三种类型下,如果被lock时(即使是当前线程lock)会立即返回。
PTHREAD_MUTEX_DEFAULT,默认值,对上述两种行为未定义,如果存在时使用以上三种类型。
以上几种属性组合后的影响如下:
mutext类型 | 健壮属性 | 重复加锁 | 没加锁时unlock或重复unlock |
PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_STALLED | 产生死锁 | 未定义的行为 |
PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_ROBUST | 产生死锁 | 返回错误 |
PTHREAD_MUTEX_ERRORCHECK | 任意 | 返回错误 | 返回错误 |
PTHREAD_MUTEX_RECURSIVE | 任意 | 递归加锁 | 返回错误 |
PTHREAD_MUTEX_DEFAULT | PTHREAD_MUTEX_STALLED | 未定义的行为 | 未定义的行为 |
PTHREAD_MUTEX_DEFAULT | PTHREAD_MUTEX_ROBUST | 未定义的行为 | 返回错误 |
带等待超时的接口
#include <pthread.h>
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timesec *restrict tsptr);
在尝试加锁时,可以设置tsptr超时时间;这样可以避免死锁的发生。
代码演示
在我的gitcode工程中,链接如下:
韩楚风 / hatchCode · GitCode
以往都会在博客中粘贴代码,发现代码多时,在博客中就看不清代码结构,幸好csdn也开放了gitcode,这样可以看到整个代码,并且可以完整下载运行。
本次的代码路径为hatchCode/ex04_process,实现了多进程间的互斥锁演示,大家也可以在此代码框加上继续开发。
[senllang@localhost ex04_process]$ pwd
/home/senllang/Dev/hatchCode/ex04_process[senllang@localhost ex04_process]$ ll
total 32
-rw-r--r--. 1 senllang develops 2273 May 3 12:05 ipc_mutex.c
-rw-r--r--. 1 senllang develops 955 May 3 12:05 ipc_mutex.h
-rw-r--r--. 1 senllang develops 1526 May 3 12:05 ipc_shmem.c
-rw-r--r--. 1 senllang develops 719 May 3 12:05 ipc_shmem.h
-rw-r--r--. 1 senllang develops 1506 May 3 12:05 main.c
-rw-r--r--. 1 senllang develops 1497 May 3 12:05 Makefile
-rw-r--r--. 1 senllang develops 1243 May 3 12:05 process.c
-rw-r--r--. 1 senllang develops 690 May 3 12:05 process.h
结尾
作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。另外有什么想要了解的内容,也可以给我发邮件,互相谈讨,定知无不言。
注:未经同意,不得转载!