既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
本质上,互斥锁就是一个全局变量,它只有 “lock” 和 “unlock” 两个值,含义分别是:
- “unlock” 表示当前资源可以访问,第一个访问资源的线程负责将互斥锁的值改为 “lock”,访问完成后再重置为“unlock”;
- “lock” 表示有线程正在访问资源,其它线程需等待互斥锁的值为 “unlock” 后才能开始访问。
通过对资源进行 "加锁(lock)"和 “解锁(unlock)”,可以确保同一时刻最多有 1 个线程访问该资源,从根本上避免了“多线程抢夺资源”的情况发生。
再次强调,对资源进行“加锁”和“解锁”操作的必须是同一个线程。换句话说,哪个线程对资源执行了“加锁”操作,那么“解锁”操作也必须由该线程负责。
互斥锁的用法
POSIX 标准规定,用 pthread_mutex_t 类型的变量来表示一个互斥锁,该类型以结构体的形式定义在<pthread.h>
头文件中。举个例子:
pthread_mutex_t myMutex;
我们成功地定义了一个名为 myMutex 的互斥锁,但要想使用它,还要进行初始化操作。
1) 互斥锁的初始化
初始化 pthread_mutex_t 变量的方式有两种,分别为:
//1、使用特定的宏
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
//2、调用初始化的函数
pthread_mutex_t myMutex;
pthread_mutex_init(&myMutex , NULL);
以上两种初始化方式是完全等价的,PTHREAD_MUTEX_INITIALIZER 宏和 pthread_mutex_init() 函数都定义在 <pthread.h> 头文件中,它们的主要区别在于:
- pthread_mutex_init() 函数可以自定义互斥锁的属性(具体自定义的方法,这里不再进行讲解)。
- 对于调用 malloc() 函数分配动态内存的互斥锁,只能以第 2 种方法完成初始化;
pthread_mutex_init() 函数专门用于初始化互斥锁,语法格式如下:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
mutex 参数表示要初始化的互斥锁;attr 参数用于自定义新建互斥锁的属性,attr 的值为 NULL 时表示以默认属性创建互斥锁。
pthread_mutex_init() 函数成功完成初始化操作时,返回数字 0;如果初始化失败,函数返回非零数。
注意,不能对一个已经初始化过的互斥锁再进行初始化操作,否则会导致程序出现无法预料的错误。
2) 互斥锁的“加锁”和“解锁”
对于互斥锁的“加锁”和“解锁”操作,常用的函数有以下 3 种:
int pthread_mutex_lock(pthread_mutex_t* mutex); //实现加锁
int pthread_mutex_trylock(pthread_mutex_t* mutex); //实现加锁
int pthread_mutex_unlock(pthread_mutex_t* mutex); //实现解锁
参数 mutex 表示我们要操控的互斥锁。函数执行成功时返回数字 0,否则返回非零数。
pthread_mutex_unlock() 函数用于对指定互斥锁进行“解锁”操作,pthread_mutex_lock() 和 pthread_mutex_trylock() 函数都用于实现“加锁”操作,不同之处在于当互斥锁已经处于“加锁”状态时:
- 执行 pthread_mutex_lock() 函数会使线程进入等待(阻塞)状态,直至互斥锁得到释放;
- 执行 pthread_mutex_trylock() 函数不会阻塞线程,直接返回非零数(表示加锁失败)。
3) 互斥锁的销毁
对于使用动态内存创建的互斥锁,例如:
pthread_mutex_t myMutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));pthread_mutex_init(&myMutex , NULL);
手动释放 myMutex 占用的内存(调用 free() 函数)之前,必须先调用 pthread_mutex_destory() 函数销毁该对象。
pthread_mutex_destory() 函数用于销毁创建好的互斥锁,语法格式如下:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数 mutex 表示要销毁的互斥锁。如果函数成功销毁指定的互斥锁,返回数字 0,反之返回非零数。
注意,对于用 PTHREAD_MUTEX_INITIALIZER 或者 pthread_mutex_init() 函数直接初始化的互斥锁,无需调用 pthread_mutex_destory() 函数手动销毁。
互斥锁的实际应用
接下来,我们使用互斥锁对《线程同步机制》一节中模拟“4 个售票员卖 10 张票”的程序进行改良,如下所示:
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
涵盖了95%以上Go语言开发知识点,真正体系化!**
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新