一.概述                                                  

互斥量是线程同步的一种机制,用来保护多线程的共享资源。同一时刻,只允许一个线程对临界区进行访问。

互斥量的工作流程:创建一个互斥量,把这个互斥量的加锁调用放在临界区的开始位置,解锁调用放到临界区的结束位置。当内核优先把某个线程调度到临界区的开始位置时,线程执行这个加锁调用,并进入临界区对资源进行操作。此时其他线程再被内核调度到这里的时候,由于该互斥量已被加锁状态,得不到锁会一直阻塞在这里,导致其他线程不能进入临界区,直到刚刚那个进入临界区的线程离开临界区并执行解锁调用。

二.函数接口                                           

1.初始化互斥量

互斥量是一个pthread_mutex_t类型的变量。

1.1:用宏常量初始化:

1 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

1.2:用函数初始化:

1 #include <pthread.h>
2
3 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

mutex:互斥量结构指针

attr:互斥量的属性结构指针

2.设置互斥量属性

1 #include <pthread.h>
2
3 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

attr:互斥量的属性结构指针

type:PTHREAD_MUTEX_NORMAL(默认属性),PTHREAD_MUTEX_ERRORCHECK(会进行错误检查,速度比较慢),PTHREAD_MUTEX_RECURSIVE(递归锁)。对于递归锁,同一个线程对一个递归锁加锁多次,会有一个锁计数器,解锁的时候也需要解锁这个次数才能释放该互斥量。

3.加锁与解锁

1 #include <pthread.h>
2
3 int pthread_mutex_lock(pthread_mutex_t *mutex);
4 int pthread_mutex_trylock(pthread_mutex_t *mutex);
5 int pthread_mutex_unlock(pthread_mutex_t *mutex);

参数都是互斥量指针。pthread_mutex_lock()得不到锁会阻塞,int pthread_mutex_trylock()得不到锁会立即返回,并返回EBUSY错误。

还有一个pthread_mutex_timedlock()会根据时间来等待加锁,如果这段时间得不到锁会返回ETIMEDOUT错误!

1 #include <pthread.h>
2 #include <time.h>
3
4 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);

4.销毁互斥量

1 #include <pthread.h>
2
3 int pthread_mutex_destroy(pthread_mutex_t *mutex);

mutex:创建的互斥量指针

三.简单例子                                            

写个简单的例子,主线程消费,子线程生产,并模拟使用过程中可能遇到的缺点

 1 /**
 2  * @file pthread_mutex.c
 3  */
 4
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <unistd.h>
 9 #include <pthread.h>
10
11 /* 定义互斥量 */
12 pthread_mutex_t mtx;
13 /* 互斥量属性 */
14 pthread_mutexattr_t mtx_attr;
15 /* 全局资源 */
16 int money;
17
18 void err_exit(const char *err_msg)
19 {
20     printf("error:%s\n", err_msg);
21     exit(1);
22 }
23
24 /* 线程函数 */
25 void *thread_fun(void *arg)
26 {
27     while (1)
28     {
29         /* 加锁 */
30         pthread_mutex_lock(&mtx);
31
32         printf("子线程进入临界区查看money\n");
33         if (money == 0)
34         {
35             money += 200;
36             printf("子线程:money = %d\n", money);
37         }
38
39         /* 解锁 */
40         pthread_mutex_unlock(&mtx);
41
42         sleep(1);
43     }
44
45     return NULL;
46 }
47
48 int main(void)
49 {
50     pthread_t tid;
51
52     /* 初始化互斥量属性 */
53     if (pthread_mutexattr_init(&mtx_attr) == -1)
54         err_exit("pthread_mutexattr_init()");
55
56     /* 设置互斥量属性 */
57     if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1)
58         err_exit("pthread_mutexattr_settype()");
59
60     /* 初始化互斥量 */
61     if (pthread_mutex_init(&mtx, &mtx_attr) == -1)
62         err_exit("pthread_mutex_init()");
63
64     /* 创建一个线程 */
65     if (pthread_create(&tid, NULL, thread_fun, NULL)== -1)
66         err_exit("pthread_create()");
67
68     money = 1000;
69     while (1)
70     {
71         /* 加锁 */
72         pthread_mutex_lock(&mtx);
73
74         if (money > 0)
75         {
76             money -= 100;
77             printf("主线程:money = %d\n", money);
78         }
79
80         /* 解锁 */
81         pthread_mutex_unlock(&mtx);
82
83         sleep(1);
84     }
85
86     return 0;
87 }

主线程和子线程都对money的操作进行了互斥量保护。68行,初始化money是1000,主线程每次消耗100,子线程只有到money是0是才会生产。sleep(1)防止独占cpu,也方便打印信息。编译运行:

可以看到这里有个非常浪费资源的问题:主线程消耗money的时候,子线程它不知道什么时候才消耗完,每次内核调度到它时,它都进入临界区加锁互斥量,然后查看money,再解锁。这无意义的操作,简直是极大的浪费!有什么办法可以解决这个问题呢?它有一个好伙伴,叫条件变量。

四.死锁                                                  

假设:当线程1获取锁1,再获取锁2后才能进入临界区1,线程2获取锁2,再获取锁1才能进入临界区2。某个时刻,线程1获取了锁1,再去获取锁2的时候发现锁2已经被线程2锁住了,而线程2获取锁2后,发现锁1被线程1锁住了。这样2个线程谁也不让谁,都进不了自己的临界区,就产生了死锁现象!一般遇到这种情况常见的解决办法是:规定统一的加锁顺序。线程1和线程2都按照先锁1,再锁2。还一种就是使用pthread_mutex_trylock(),如果该函数返回EBUSY错误,就释放这个线程的所有锁,不过效率有点低。

linux线程同步(1)-互斥量相关推荐

  1. 信号灯文件锁linux线程,linux——线程同步(互斥量、条件变量、信号灯、文件锁)...

    一.说明 linux的线程同步涉及: 1.互斥量 2.条件变量 3.信号灯 4.文件读写锁 信号灯很多时候被称为信号量,但个人仍觉得叫做信号灯比较好,因为可以与"SYSTEM V IPC的信 ...

  2. linux线程同步之互斥锁——linux的关键区域

    在windows中,为了让多个线程达到同步的目的,在对于全局变量等大家都要用的资源的使用上,通常得保证同时只能由一个线程在用,一个线程没有宣布对它的释放之前,不能够给其他线程使用这个变量.在windo ...

  3. 并发编程概念、程序线程进程、线程同步、互斥量、读写锁、协程并发

    多线程: 多线程就是同时执行多个应用程序,需要硬件的支持 同时执行:不是某个时间段同时,cpu切换的比较快,所有用户会感觉是在同时运行 并发与并行: 并行(parallel):指在同一时刻,有多条指令 ...

  4. 线程同步之互斥量(互斥锁)

    1 同步的概念 所谓同步, 即同时起步,协调一致.不同的对象, 对"同步" 的理解方式略有不同. 如,设备同步,是指在两个设备之间规定一个共同的时间参考: 数据库同步, 是指让两个 ...

  5. Linux线程同步(二)---互斥锁实现线程同步

    一 why 先给自己打个广告,本人的微信公众号:嵌入式Linux江湖,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题. 在博客&l ...

  6. 1线程同步:互斥量,死锁

     1线程为什么要同步 A:共享资源,多个线程都可对共享资源操作. B:线程操作共享资源的先后顺序不确定. C:处理器对存储器的操作一般不是原子操作. 2互斥量 mutex操作原语 pthread_ ...

  7. RTT的线程同步篇——互斥量

    野火RTT第20章互斥量 2018年12月29日 10:47 互斥量不能在中断服务程序中使用. 互斥量是特殊的二值信号量,其"特殊"在哪呢?互斥量不同于二值信号量的地方在于:互斥量 ...

  8. 线程同步之互斥量加锁解锁 死锁

    与互斥锁相关API       互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁.对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程将会被阻 ...

  9. linux操作系统之线程同步及互斥量

    (1)线程同步 1)线程同步:指一个线程发出某一个功能运行时,在运行还没有结束的时候,该调用不返回.同时其它线程为保证数据的一致性,不能调用该功能. 2)多个控制流共同操作一个共享资源的时候,都需要同 ...

最新文章

  1. ICLR 2022论文列表公布,接收率高达32%
  2. acm java_ACM Java Native SDK 概述
  3. 致年轻开发人员的一封信
  4. 如何修改emcp的sn号_百家号领域选择错误怎么办?百家号怎么更改领域?
  5. 点餐系统ip地址_spring boot实战——微信点餐系统03:微信授权(用户授权),免费内网穿透(固定ip)...
  6. C# 最简单的异步委托
  7. 入选《PHP领域内容榜》,感谢CSDN,感谢各位浏览过我的朋友
  8. 英文 WINDOWS XP 专业 精简版
  9. Think Python读书笔记及课后习题---【前三章】
  10. BA-业务架构_优化“价值主张画布”,助力企业数字化赋能
  11. vue--百度地图之离线地图--大量标注点造成卡顿问题--海量点聚合性能优化
  12. pycharm专业版 激活+汉化
  13. 打工人必备的效率工具软件,这3款你get了吗?
  14. 4002—Ajax随笔
  15. 吴恩达DeepLearning课后习题
  16. Springboot简单授权,限制访问
  17. 大二物竞金牌转北大计算机,高二全国数学竞赛
  18. 买英伟达RTX 30 系显卡送《穿越火线》大礼包,你心动了吗?
  19. 推荐阅读:《我在赶集网的两个月》
  20. 独立站即web3.0,国家“十四五“规划要求企业建数字化网站!

热门文章

  1. 前端解析Excel文件js-xlsx与bootstrapTable
  2. 集合相等问题_JAVA
  3. C语言实验——矩阵转置_JAVA
  4. tesseract识别图片中文字(一)
  5. 【C++】40. std::array与int a[]方式创建数组的区别
  6. 20180530更新
  7. 十个免费的WEB压力测试工具
  8. C# vs C++ 全局照明渲染性能比试
  9. OpenCV学习笔记(四十一)——再看基础数据结构core OpenCV学习笔记(四十二)——Mat数据操作之普通青年、文艺青年、暴力青年 OpenCV学习笔记(四十三)——存取像素值操作汇总co
  10. 漫谈:机器学习中距离和相似性度量方法