linux 互斥量pthread_mutex

  


目录

前言

概述

原理

初始化

进程和线程使用的不同点

死锁

接口

基本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

 


结尾

作者邮箱:[email protected]
如有错误或者疏漏欢迎指出,互相学习。另外有什么想要了解的内容,也可以给我发邮件,互相谈讨,定知无不言。

注:未经同意,不得转载!

猜你喜欢

转载自blog.csdn.net/senllang/article/details/130471754