linux线程同步(1)-互斥量

一.概述

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

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

二.函数接口

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. Linux线程-互斥锁pthread_mutex_t

    Linux线程-互斥锁pthread_mutex_t 在线程实际运行过程中,我们经常需要多个线程保持同步.这时可以用互斥锁来完成任务:互斥锁的使用过程中,主要有pthread_mutex_init, ...

  2. Linux线程-互斥锁pthread_mutex_t

    在线程实际运行过程中,我们经常需要多个线程保持同步.这时可以用互斥锁来完成任务:互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthrea ...

  3. linux进程线程同步之 - POSIX线程互斥锁

    POSIX线程互斥锁 使用范围:线程同步 本文转自:http://blog.csdn.net/jiebaoabcabc/article/details/37914769 一.函数介绍 1.初始化互斥锁 ...

  4. Linux线程互斥学习笔记--详细分析

    一.互斥锁 为啥要有互斥? 多个进程/线程执行的先后顺序不确定,何时切出CPU也不确定. 多个进程/线程访问变量的动作往往不是原子的. 1. 操作步骤 (1)创建锁 // 创建互斥锁mutex pth ...

  5. Python 线程互斥锁 Lock - Python零基础入门教程

    目录 一.前言 二.Python 线程共享全局变量 三.Python 线程互斥锁 1.创建互斥锁 2.锁定资源/解锁资源 四.Python 线程死锁 五.重点总结 六.猜你喜欢 一.前言 在前一篇文章 ...

  6. python-生产者消费者模型_线程_线程互斥锁_GIL全局解释器锁

    进程 1. 开启进程的两种方式 2. 进程对象其他属性和方法-pid: 进程id号 os.getpid()-ppid: 父进程id号 os.getppid() -is_alive(): 当前进程是否存 ...

  7. 网络编程-线程,守护线程,线程互斥锁-26

    网络编程-线程,守护线程,线程互斥锁-26 内容: 进程部分: 进程间通信=>IPC 生产者消费者模型() 线程部分: 1. 线程理论() 2.开启线程的两种方式() 3. 线程对象其他相关的属 ...

  8. linux内核互斥锁

    Linux内核互斥锁–mutex 一.定义: /linux/include/linux/mutex.h 二.作用及访问规则: 互斥锁主要用于实现内核中的互斥访问功能.内核互斥锁是在原子 API 之上实 ...

  9. android 线程互斥锁,线程锁(互斥锁Mutex)及递归锁

    一.线程锁(互斥锁) 在一个程序内,主进程可以启动很多个线程,这些线程都可以访问主进程的内存空间,在Python中虽然有了GIL,同一时间只有一个线程在运行,可是这些线程的调度都归系统,操作系统有自身 ...

最新文章

  1. Shell 开发在运维中的经验总结
  2. 北大数学天才许晨阳,回国效力6年后,为什么又去了美国任教?
  3. 由浅入深CIL系列【目录索引】+ PostSharp AOP编程【目录索引】
  4. 编辑从字节码和 JVM 的角度解析 Java 核心类 String 的不可变特性
  5. K8S完整部署项目实战案例
  6. 基于Arduino开发的智能蓝牙小车
  7. python编写交互界面查分app_Django项目中model的数据处理以及页面交互方法
  8. 网络对抗技术实验二,第一部分,第二部分
  9. 金蝶显示服务器不是有效,金蝶 服务器不是有效的 请重新设置
  10. 【语音判别】基于matlab双门限法判别语音信号【含Matlab源码 1720期】
  11. 3d游戏建模都需要准备些什么
  12. vb 运行错误429 mysql_”运行时错误429:activex部件不能创建对象。“
  13. 2009年毕业设计题目:网上自助装机系统的设计与实现
  14. COBIT(cobit框架)
  15. 【组网工程】cisco packet tracer 路由器组网
  16. 空气源热泵设备远程监控的优点
  17. openstack queens版本修改admin密码
  18. 被Facebook开除的中国工程师:我不后悔那天的决定
  19. 计算机毕业设计Node.js+Express母婴商品店进出货管理系统(源码+程序+lw+远程调试)
  20. Mac os下时间戳转换

热门文章

  1. vue3本地图片加载不出来,解决方法
  2. 智能家居前装好还是后装好?哪个才是全屋智能更好的选择?
  3. 腾讯视频显示已开启服务器,怎么看自己是否开通了腾讯视频会员?查看腾讯视频会员状态方法介绍...
  4. 最近知识的总结与复习
  5. 数据永久保存?有人要把资料存月球上
  6. 【BYOD】自带设备 资料
  7. 软件实施工程师面试总结
  8. E-puck机器人-小白学习笔记(二)代码浅解读
  9. 以信息技术促进小学数学探究学习
  10. 51单片机红外电子密码锁【红外对管矩阵键盘数码管LCD1602显示模块】