LINUX - pthread_mutex_lock
原文链接:https://www.cnblogs.com/fengbohello/p/7571722.html
互斥的概念
在多线程编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。 每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻, 只能有一个线程访问该对象。
互斥锁操作
互斥锁也可以叫线程锁,接下来说说互斥锁的的使用方法。
对互斥锁进行操作的函数,常用的有如下几个:

#include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);

对线程锁进行操作的函数有很多,还包括许多线程锁属性的操作函数, 不过一般来说,对于并不复杂的情况, 只需要使用创建、获取锁、释放锁、删除锁这几个就足够了。
创建互斥锁
所以下面简单看一下如何创建和使用互斥锁。
在使用互斥锁之前,需要先创建一个互斥锁的对象。 互斥锁的类型是 pthread_mutex_t ,所以定义一个变量就是创建了一个互斥锁。
pthread_mutex_t mtx;
这就定义了一个互斥锁。但是如果想使用这个互斥锁还是不行的,我们还需要对这个互斥锁进行初始化, 使用函数 pthread_mutex_init() 对互斥锁进行初始化操作。
//第二个参数是 NULL 的话,互斥锁的属性会设置为默认属性
pthread_mutex_init(&mtx, NULL);
除了使用 pthread_mutex_init() 初始化一个互斥锁,我们还可以使用下面的方式定义一个互斥锁:
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
在头文件 /usr/include/pthread.h 中,对 PTHREAD_MUTEX_INITIALIZER 的声明如下
# define PTHREAD_MUTEX_INITIALIZER \
{ { 0, 0, 0, 0, 0, 0, { 0, 0 } } }
为什么可以这样初始化呢,因为互斥锁的类型 pthread_mutex_t 是一个联合体, 其声明在文件 /usr/include/bits/pthreadtypes.h 中,代码如下:

/* Data structures for mutex handling. The structure of the attribute
type is not exposed on purpose. */
typedef union
{
struct __pthread_mutex_s
{
int __lock;
unsigned int __count;
int __owner;
#if __WORDSIZE == 64
unsigned int __nusers;
#endif
/* KIND must stay at this position in the structure to maintain
binary compatibility. */
int __kind;
#if __WORDSIZE == 64
int __spins;
__pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV 1
#else
unsigned int __nusers;
__extension__ union
{
int __spins;
__pthread_slist_t __list;
};
#endif
} __data;
char __size[__SIZEOF_PTHREAD_MUTEX_T];
long int __align;
} pthread_mutex_t;

获取互斥锁
接下来是如何使用互斥锁进行互斥操作。在进行互斥操作的时候, 应该先"拿到锁"再执行需要互斥的操作,否则可能会导致多个线程都需要访问的数据结果不一致。 例如在一个线程在试图修改一个变量的时候,另一个线程也试图去修改这个变量, 那就很可能让后修改的这个线程把前面线程所做的修改覆盖了。
下面是获取锁的操作:
阻塞调用
pthread_mutex_lock(&mtx);
这个操作是阻塞调用的,也就是说,如果这个锁此时正在被其它线程占用, 那么 pthread_mutex_lock() 调用会进入到这个锁的排队队列中,并会进入阻塞状态, 直到拿到锁之后才会返回。
非阻塞调用
如果不想阻塞,而是想尝试获取一下,如果锁被占用咱就不用,如果没被占用那就用, 这该怎么实现呢?可以使用 pthread_mutex_trylock() 函数。 这个函数和 pthread_mutex_lock() 用法一样,只不过当请求的锁正在被占用的时候, 不会进入阻塞状态,而是立刻返回,并返回一个错误代码 EBUSY,意思是说, 有其它线程正在使用这个锁。

int err = pthread_mutex_trylock(&mtx);
if(0 != err) {
if(EBUSY == err) {
//The mutex could not be acquired because it was already locked.
}
}

超时调用
如果不想不断的调用 pthread_mutex_trylock() 来测试互斥锁是否可用, 而是想阻塞调用,但是增加一个超时时间呢,那么可以使用 pthread_mutex_timedlock() 来解决, 其调用方式如下:

struct timespec abs_timeout;
abs_timeout.tv_sec = time(NULL) + 1;
abs_timeout.tv_nsec = 0; int err = pthread_mutex_timedlock(&mtx, &abs_timeout);
if(0 != err) {
if(ETIMEDOUT == err) {
//The mutex could not be locked before the specified timeout expired.
}
}

上面代码的意思是,阻塞等待线程锁,但是只等1秒钟,一秒钟后如果还没拿到锁的话, 那就返回,并返回一个错误代码 ETIMEDOUT,意思是超时了。
其中 timespec 定义在头文件 time.h 中,其定义如下
struct timespec
{
__time_t tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
};
还需要注意的是,这个函数里面的时间,是绝对时间,所以这里用 time() 函数返回的时间增加了 1 秒。
释放互斥锁
用完了互斥锁,一定要记得释放,不然下一个想要获得这个锁的线程, 就只能去等着了,如果那个线程很不幸的使用了阻塞等待,那就悲催了。
释放互斥锁比较简单,使用 pthread_mutex_unlock() 即可:
pthread_mutex_unlock(&mtx);
销毁线程锁
通过 man pthread_mutex_destroy 命令可以看到 pthread_mutex_destroy() 函数的说明, 在使用此函数销毁一个线程锁后,线程锁的状态变为"未定义"。有的 pthread_mutex_destroy 实现方式,会使线程锁变为一个不可用的值。一个被销毁的线程锁可以被 pthread_mutex_init() 再次初始化。对被销毁的线程锁进行其它操作,其结果是未定义的。
对一个处于已初始化但未锁定状态的线程锁进行销毁是安全的。尽量避免对一个处于锁定状态的线程锁进行销毁操作。
销毁线程锁的操作如下:
pthread_mutex_destroy(&mtx)
LINUX - pthread_mutex_lock的更多相关文章
- windows 和linux 同步api对比
初始化临界区 (win) InitializeCriticalSection(RTL_CRITICAL_SECTION &rtl_critial_section) (linux) pthrea ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- Linux Socket 网络编程
Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...
- linux内核数据结构之kfifo
1.前言 最近项目中用到一个环形缓冲区(ring buffer),代码是由linux内核的kfifo改过来的.缓冲区在文件系统中经常用到,通过缓冲区缓解cpu读写内存和读写磁盘的速度.例如一个进程A产 ...
- linux c/c++
string 字符串操作 操作数的都是 ( char * )型,操作数必须是指向字符串的指针("a"),不能是字符('a'),操作时不考虑末尾的'\0'. size_t strle ...
- Linux 线程管理
解析1 LINUX环境下多线程编程肯定会遇到需要条件变量的情况,此时必然要使用pthread_cond_wait()函数.但这个函数的执行过程比较难于理解. pthread_cond_wait()的工 ...
- linux线程
线程:轻量级进程,在资源.数据方面不需要进行复制 不间断地跟踪指令执行的路径被称为执行路线 进程的结构:task_struck:地址空间 线程:轻量级的进程 在同一个进程中创建的线程,在共享进程的地址 ...
- 【linux草鞋应用编程系列】_4_ 应用程序多线程
一.应用程序多线程 当一个计算机上具有多个CPU核心的时候,每个CPU核心都可以执行代码,此时如果使用单线程,那么这个线程只能在一个 CPU上运行,那么其他的CPU核心就处于空闲状态,浪费了系 ...
- Linux下c开发 之 线程通信(转)
Linux下c开发 之 线程通信(转) 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linu ...
随机推荐
- jQuery库 之 jquery slimscroll插件使用
1.引入jQuery插件 <script type="text/javascript" src="jquery.min.js"></scrip ...
- STM32驱动LCD实战
前段时间写了<STM32驱动LCD原理>和<STM32的FSMC外设简介>两篇文章,本文将对STM32驱动LCD进行实战应用.LCD是深圳市拓普微科技开发有限公司的LMT028 ...
- 使用Spring的RestTemplate进行接口调用
引自:http://www.zimug.com/ 1.常见的http服务的通信方式 经常使用的方式有HttpClient.OkHttp.RestTemplate.其中RestTemplate是一种更优 ...
- scrapy异步的爬虫框架简单的使用
scrapy异步的爬虫框架 异步的爬虫框架 高性能的数据解析,持久化存储,全栈数据的爬取,中间件,分布式 框架:就是一个集成好了各种功能且具有很强通用性的一个项目模板. 环境安装: Linux: pi ...
- centos&linux
who am i 查看是哪一个用户 init 0关机 ifconfig用于配置网络或显示当前网络接口的状态 eth0是网卡的名字 第一行:flags后面的up指的是网卡处于运行状态,running连接 ...
- Flink的状态与容错
本文主要运行到Flink以下内容 检查点机制(CheckPoint) 状态管理器(StateBackend) 状态周期(StateTtlConfig) 关系 首先要将state和checkpoint概 ...
- Vue整合swiper报错Could not compile template .....swiper\dist\css\swiper.css解决办法
问题描述 今天做一个前端项目,安装幻灯片插件vue-awesome-swiper后 运行npm run dev 后报错如下: `ERROR Could not compile template E:\ ...
- Asp.netCore 3.1控制器属性注入and异步事务Aop by AutoFac
Aspect Oriented Programming(AOP)是较为热门的一个话题.AOP,国内我们都习惯称之为:面向切面编程 下面直接code 干货展示:(一般人我还不告诉,嘻嘻) 1:导入相关的 ...
- 使用Robo 3T操作MongoDB数据库
安装Robo 3T连接MongoDB数据库教程:https://blog.csdn.net/baidu_39298625/article/details/98845789 在IDEA中用三个jar包链 ...
- 在Centos7上安装Python+Selenium+Chrome+Chromedriver
1.下载Chrome 上一篇文章已经演示过了Python+Selenium+Firefox+Geckodriver安装步骤并通过自动化脚本打开百度 因此当前只需要安装Chrome和Chromedriv ...