一、线程互斥的概念
1.1临界资源与互斥的关系
1.2互斥量mutex
// 操作共享变量会有问题的售票系统代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int ticket = 100;
void* route(void* arg)
{char* id = (char*)arg;while (1) {if (ticket > 0) {usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;}else {break;}}
}
如上图所示,票到最后被枪成了负数而其原因就是代码中没有对临界区资源进行保护,加上临界区对临界资源的操作也并不是原子的,所以最终导致票数成了负数。
1.3汇编角度分析
取出ticket--部分的汇编代码
objdump -d a.out > test.objdump
152 40064b: 8b 05 e3 04 20 00 mov 0x2004e3(%rip),%eax # 600b34 <ticket>
153 400651: 83 e8 01 sub $0x1,%eax
154 400654: 89 05 da 04 20 00 mov %eax,0x2004da(%rip) # 600b34 <ticket>
二、互斥量(锁)的接口
2.1初始化互斥量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutex_t* restrict mutex,const pthread_mutexattr_t* restrict attr);
参数:
mutex:要初始化的互斥量
attr:NULL
2.2申请及使用锁
加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
申请锁会出现以下几种状态:
1、申请成功:函数就会返回,允许继续运行。
2、申请失败:函数就会阻塞,不允许继续往下执行。
3、函数调用失败,出错返回。
解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
尝试申请锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
三、互斥量实现原理
int ticket = 100;
pthread_mutex_t mutex;
void* route(void* arg)
{char* id = (char*)arg;while (1) {pthread_mutex_lock(&mutex);if (ticket > 0) {usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;pthread_mutex_unlock(&mutex);// sched_yield(); 放弃CPU}else {pthread_mutex_unlock(&mutex);break;}}
}
通俗来讲:调用锁以后,CPU内会存在一个al寄存器内部存储一个0,在申请锁时,内存中存在mutex内部为1,在一个线程调用锁时,CPU会将al和mutex中的值直接交换,如果此时al为1则说明申请成功,而该线程被中断后会将CPU寄存器中自己的上下文数据全部带走,此时al和mutex中都是0,当下一个线程申请锁时,al交换到的mutex中的内容还是0,此时就只能挂起等待别的线程将锁归还。