1.互斥锁作用
在Linux下,多个线程拥有同一个虚拟地址空间,若多个线程对同一块数据进行操作,可能会产生二义性。造成逻辑混乱。为了保证不发生这些,就需要线程安全。
线程安全的概念:多个线程对同一个临界资源进行争抢访问,但不会造成数据二义性。
线程安全的实现:就要保证同步与互斥。
同步的实现:条件变量/信号量
互斥的实现:互斥锁/信号量
互斥锁为资源引入一个状态信息:锁定/非锁定
当线程要访问一个临界资源的时候,需要先查看这个锁的状态信息
1.若处于开锁(非锁定)状态,就申请到了对临界资源的访问权,并立即更改锁的状态置为锁定状态。
2.若处于锁定状态,则当前线程阻塞,有R(运行)状态变成S(休眠)状态。
2.互斥锁操作
1.定义互斥锁变量
pthread_mutex_t 是一个结构体,锁的类型就是这个。
2.初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
第一个参数传递定义的互斥锁的指针,第二个参数是设置互斥锁的属性
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
这种在定义的时候初始化的方式也可以,POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来初始化锁。
3.上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
阻塞接口
int pthread_mutex_trylock(pthread_mutex_t *mutex);
非阻塞接口
4.解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
5.销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
3.互斥锁原理
在pthread_mutex_t结构体中,有一个变量,当它不为0的时候,线程可以继续执行,否则线程被阻塞。当解锁的时候,会进行唤醒操作,唤醒因为没有获取锁而阻塞的线程。
点这里,这个博客里具体讲了加锁解锁的原理
对锁的状态判断和修改锁的值是一个原子操作,否则可能会导致,一个线程刚判断完可以访问资源进行加锁,另一个线程也正在判断。那这样两个线程可能都会对资源进行访问。
这个原子操作的原理是
1.首先在寄存器里面设置一个变量0。
2.在对锁访问的时候会有一个原子操作,将内存中锁中的值和寄存器中的这个0进行交换。
3.再去判断寄存器中的值,如果是1则可以获取锁,如果是0,就无法获得锁。
4.互斥锁实例–大妈抢鸡蛋
//通过大妈抢鸡蛋的例子,体会线程安全的重要性以及认识了解互斥锁
//每个线程代表一个大妈。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#define MAX_THR 4 //设置创建线程数量
pthread_mutex_t _mutex;//创建互斥锁变量
int egg = 100;//设置100个鸡蛋
void *Dama(void *arg)
{
while(1)
{
pthread_mutex_lock(&_mutex);//先上锁,让其他线程阻塞
if(egg > 0)
{
printf("%p抢到了第%d个鸡蛋\n",pthread_self(),egg--);
//大妈每次抢一个鸡蛋
}
else
{
printf("鸡蛋抢完了\n");
pthread_mutex_unlock(&_mutex);//解锁后退出线程
pthread_exit(NULL);
}
pthread_mutex_unlock(&_mutex);//抢到了进行解锁
usleep(100);
}
return NULL;
}
int main()
{
int i;
pthread_t tid[MAX_THR];//线程ID
pthread_mutex_init(&_mutex,NULL);//互斥锁初始化
for(i = 0;i < MAX_THR; i++)
{
int ret = pthread_create(&tid[i],NULL,Dama,NULL);//创建线程
//参数解释:
//1.保存当前线程ID
//2.设置线程属性
//3.设置线程要去执行的函数地址
//4.需要给线程函数中传递的参数
if(ret!=0)//判断线程是否为创建失败
{
perror("pthread error\n");
return -1;
}
}
for(i = 0;i < MAX_THR; i++)
{
pthread_join(tid[i],NULL);//线程等待
}
pthread_mutex_destroy(&_mutex);//销毁互斥锁
return 0;
}