互斥锁的属性

简介: 互斥锁的属性

在笔记互斥锁的死锁中,初始化互斥锁 pthread_mutex_init() 函数中参数 attr 为指定互斥锁的属性,而一般默认传参为 NULL ,表示执行该互斥锁的默认属性。本笔记单独讨论互斥锁的属性。

#include <pthread.h>
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);点击复制复制失败已复制


pthread_mutexattr_init() 函数为初始化互斥锁属性,一般采用默认的方式传参。 pthread_mutexattr_destroy() 函数摧毁互斥锁属性。

#include <pthread.h>
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);点击复制复制失败已复制


pthread_mutexattr_getpshared() 函数和 pthread_mutexattr_setpshared() 函数的功能分别为获得互斥锁的属性、设置互斥锁的属性。参数 attr 表示互斥锁的属性。参数 pshared 可以设置为两种情况:

  1. PTHREAD_PROCESS_PRIVATE,表示互斥锁只能在一个进程内部的两个线程进行互斥(默认情况
  2. PTHREAD_PROCESS_SHARED,互斥锁可用于两个不同进程中的线程进行互斥,使用时需要在共享内存中分配互斥锁,再为互斥锁指定该属性即可。


pthread_mutexattr_gettype() 函数和 pthread_mutexattr_settype() 函数用来获得以及设置互斥锁的类型。

#include <pthread.h>
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);点击复制复制失败已复制


参数 type 用来定义互斥锁的类型,其类型可以被设置为如下几种情况。

  1. PTHREAD_MUTEX_NORMAL标准互斥锁,该类型的互斥锁不具备死锁检测功能。
  2. PTHREAD_MUTEX_ERRORCHECK检错互斥锁,对此互斥锁的所有操作都会执行错误检测,这种互斥锁运行起来较一般类型慢,不过却可以作为调试,以发现后续程序在哪里违反了互斥锁的使用规则。
  3. PTHREAD_MUTEX_RECURSIVE递归互斥锁,该互斥锁维护有一个锁计数器,线程上锁则会将锁计数器的值加1,解锁则会将锁计数器的值减1。只有当锁计数器值降至0时,才会释放该互斥锁。这一类互斥锁与普通互斥锁的区别在于,同一个线程可以多次获得同一个递归锁,不会产生死锁。而如果一个线程多次获得同一个普通锁,则会产生死锁。Linux下的互斥锁默认属性为非递归的。


接下来展示函数的基本操作,注意示例只展示锁的属性设置,不创建线程执行任务。对互斥锁的属性进行初始化,之后选择命令传参设置互斥锁的类型,然后初始化互斥锁,对互斥锁进行操作,以此测试互斥锁的类型。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[]) {
  // 定义互斥锁
  pthread_mutex_t mutex;
  if (argc < 2) {
    printf("input mutex type\n");
    return -1;
  }
  // 定义互斥锁属性
  pthread_mutexattr_t mutexattr;
  // 设置互斥锁的类型,error:检错互斥锁;normal:标准互斥锁;recursive:递归互斥锁
  pthread_mutexattr_init(&mutexattr);
  if (!strcmp(argv[1], "error")) {
    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
    printf("set error success\n");
  } else if (!strcmp(argv[1], "normal")) {
    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL);
    printf("set normal success\n");
  } else if (!strcmp(argv[1], "recursive")) {
    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
    printf("set recursive success\n");
  }
  // 初始化互斥锁
  pthread_mutex_init(&mutex, &mutexattr);
  // 初次上锁
  if (pthread_mutex_lock(&mutex) != 0) {
    printf("lock failed\n");
  } else {
    printf("lock success\n");
  }
  // 第二次上锁
  if (pthread_mutex_lock(&mutex) != 0) {
    printf("lock failed\n");
  } else {
    printf("lock success\n");
  }
  // 加锁几次,同样也要释放几次
  pthread_mutex_unlock(&mutex);
  pthread_mutex_unlock(&mutex);
  // 销毁互斥锁属性和互斥锁
  pthread_mutexattr_destroy(&mutexattr);
  pthread_mutex_destroy(&mutex);
  return 0;
}点击复制复制失败已复制


给程序传入不同的参数,使互斥锁设置不同的类型,效果如下:

  • 检错互斥锁
$ gcc main2.c && ./a.out error
set error success
lock success
lock failed点击复制复制失败已复制


  • 普通互斥锁
$ gcc main2.c && ./a.out normal
set normal success
lock success
^C点击复制复制失败已复制


提示

这里程序阻塞了


  • 递归互斥锁
$ gcc main2.c && ./a.out recursive 
set recursive success
lock success
lock success
目录
相关文章
|
Android开发
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )
1005 0
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )
|
关系型数据库 MySQL 索引
从一个案例深入剖析InnoDB隐式锁和可见性判断(3)
从一个案例深入剖析InnoDB隐式锁和可见性判断
|
NoSQL 关系型数据库 索引
从一个案例深入剖析InnoDB隐式锁和可见性判断(1)
从一个案例深入剖析InnoDB隐式锁和可见性判断
121 0
从一个案例深入剖析InnoDB隐式锁和可见性判断(1)
|
存储 关系型数据库 MySQL
从一个案例深入剖析InnoDB隐式锁和可见性判断(4)
从一个案例深入剖析InnoDB隐式锁和可见性判断
|
SQL 关系型数据库 MySQL
从一个案例深入剖析InnoDB隐式锁和可见性判断(2)
从一个案例深入剖析InnoDB隐式锁和可见性判断
从一个案例深入剖析InnoDB隐式锁和可见性判断(2)
|
10月前
|
Java
递归锁解析
递归锁(Reentrant Lock)是一种可以被同一个线程多次获取的锁,它避免了死锁的发生。在Java中,ReentrantLock类实现了递归锁的机制。
320 1
|
Ubuntu Linux C语言
Linux下 tar命令(工具)的移植,源码下载、详细移植步骤
Linux下 tar命令(工具)的移植,源码下载、详细移植步骤
422 0
Linux下 tar命令(工具)的移植,源码下载、详细移植步骤
|
编解码 编译器 C语言
【FFmpeg】ffmpeg 命令查询一 ( 版本 | 编译配置 | 复用格式 | 编解码器 )(一)
【FFmpeg】ffmpeg 命令查询一 ( 版本 | 编译配置 | 复用格式 | 编解码器 )(一)
1919 0
【FFmpeg】ffmpeg 命令查询一 ( 版本 | 编译配置 | 复用格式 | 编解码器 )(一)
|
Linux
Linux—traceroute命令 – 追踪数据包在网络上的传输时的全部路径
traceroute命令用于追踪数据包在网络上的传输时的全部路径,它默认发送的数据包大小是40字节。通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径。当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一样,但基本上来说大部分时候所走的路由是相同的。
517 0
Linux—traceroute命令 – 追踪数据包在网络上的传输时的全部路径
|
存储 缓存 数据库
【整理篇】Flutter 常用第三方库、插件、学习资料等
【整理篇】Flutter 常用第三方库、插件、学习资料等
934 0