何为互斥
一种对共享数据的保护,防止多线程同时访问共享资源的时,数据混乱的问题。在互斥期间,保证执行流由并行改为串行。任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用 原子性(后面讨论如何实现):不会被任何调度机制打断的操作(有歧义,会被打断,但是无法影响对数据的访问),该操作只有两态,要么完成,要么未完成
加锁后,到解锁过程中,只允许一条执行流访问该区块代码,这就是我们所谓的原子性
互斥锁接口
锁类型名
pthread_mutex_t mtx //定义一个叫做mtx的锁
锁的声明方法(静/动态
//静态初始化锁
pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER//动态初始化锁int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t *attr);
//省略了restrict
在动态申请的初始化后,需要主动释放锁。
//对于动态申请的锁,在在最后需要手动释放锁
pthread_mutex_init(&mtx);
//。。。。//不用该锁后
pthread_mutex_destroy(&mtx);
阻塞加锁int pthread_mutex_lock
int pthread_mutex_lock (pthread_mutex_t *__mutex);
如果该锁已经被其他执行流占用,或在竞争的时没有争到锁,线程将阻塞,等待占用锁的线程释放锁后再去争夺锁的使用。
非阻塞加锁int pthread_mutex_trylock
int pthread_mutex_trylock (pthread_mutex_t *__mutex)
尝试占用锁,在未占用锁时,不会进入阻塞状态,返回错误码后继续执行后续代码。可以根据是否返回0做if判断。
释放锁int pthread_mutex_unlock
int pthread_mutex_unlock (pthread_mutex_t *__mutex)
释放__mutex锁资源。
互斥锁底层逻辑
锁其实也是共享资源,也是被多个执行流所访问,那么怎么保护加锁和释放锁的原子操作
利用汇编中的指令:swap或exchange,这两条指令是将两个数据交换的,这种交换在汇编中只有一条语句,要么交换完成要么不交换,保证原子操作。
看看加锁的伪代码
先来看看lock加锁代码的逻辑。
首先内存中锁保存了个资源1,线程1、2的上下文al都是被初始化为0的。
线程1先跑,调用lock函数,初始化al为0后交换数据
然后立刻被切换到线程二
然后线程二,走else被挂起
切换会线程1,出if成立函数lock执行后续代码
在这期间,线程2一直被阻塞,直到线程1调用unlock函数,重新写入mutex为1,注意,在代码书写不当时,拥有A锁的线程再去申请A锁将自我阻塞死锁情况。