一、为什么需要使用互斥锁
使用互斥锁(互斥)可以使线程按顺序执行,可完整执行完一个线程。通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程。互斥锁还可以保护单线程代码。
Linux 内核互斥锁是非常常用的同步机制,互斥锁是这样一种同步机制:在互斥锁中同时只能有一个任务可以访问该锁保护的共享资源,且释放锁和获得锁的调用方必须一致。因此在互斥锁中,除了对锁本身进行同步,对调用方(或称持有者)必须也进行同步。当互斥锁无法获得时,task会加入等待队列,直至可获得锁为止。
二、互斥锁的死锁
程序中运行有两个以上的线程。
场景:程序中有线程A和线程B。线程A拿到了锁1,想要获得锁2。线程B拿到了锁2,想要获得锁1。由于线程A永远无法获得到锁2,线程B永远获得不到锁1,即产生死锁。
三、互斥锁与信号量的区别
①互斥量用于线程的互斥,信号线用于线程的同步。这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
②互斥量值只能为0/1,信号量值可以为非负整数。
③互斥量值只能为0/1,信号量值可以为非负整数。
四、互斥锁常见的API
头文件
#include <pthread.h>
①创建锁及销毁锁
1.初始化锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
第一个参数为执行该互斥锁标识符的指针。
第二个要用默认的属性初始化互斥量,只需把attr设置为NULL。
2.销毁锁
int pthread_mutex_destroy(pthread_mutex_t* mutex);
返回值:若成功返回0,否则返回错误编号
②加锁和减锁操作
1.加锁(P操作)
int pthread_mutex_lock(pthread_mutex_t * mptr);
2.解锁(V操作)
int pthread_mutex_unlock(pthread_mutex_t * mptr);
注意:
在对临界资源进行操作之前需要pthread_mutex_lock先加锁,操作完之pthread_mutex_unlock再解锁。而且在这之前需要声明一个pthread_mutex_t类型的变量,用作前面两个函数的参数。
同一时间只能有一个线程获取锁
五、测试demo
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//创建线程
pthread_t id1;
pthread_t id2;
pthread_t id3;
//创建互斥锁
pthread_mutex_t m1;
//定义全局变量
int g_data=666;
void *pthreadfun1(void)
{
pthread_mutex_lock(&m1);
g_data=1;
printf("the pthread 1's pid is %ld\n",(unsigned long)pthread_self());
printf("线程1——:%d\n",g_data);
pthread_mutex_unlock(&m1);
}
void *pthreadfun2(void)
{
pthread_mutex_lock(&m1);
g_data=2;
printf("the pthread 2's pid is %ld\n",(unsigned long)pthread_self());
printf("线程2——:%d\n",g_data);
pthread_mutex_unlock(&m1);
}
void *pthreadfun3(void)
{
pthread_mutex_lock(&m1);
g_data=3;
printf("the pthread 3's pid is %ld\n",(unsigned long)pthread_self());
printf("线程3——:%d\n",g_data);
pthread_mutex_unlock(&m1);
}
int main()
{
int ret;
int retval;
retval=pthread_mutex_init(&m1,NULL);
if(retval!=0)
{
printf("create mutex error\n");
return 1;
}
ret=pthread_create(&id1,NULL,(void *)pthreadfun1,NULL);
if(ret!=0)
{
printf("create pthread error\n");
return 1;
}
ret=pthread_create(&id2,NULL,(void *)pthreadfun2,NULL);
if(ret!=0)
{
printf("create pthread error\n");
return 1;
}
ret=pthread_create(&id3,NULL,(void *)pthreadfun3,NULL);
if(ret!=0)
{
printf("create pthread error\n");
return 1;
}
printf("the main process pid is %ld\n",(unsigned long)pthread_self());
printf("主程序——:%d\n",g_data);
pthread_join(id1,NULL);
pthread_join(id2,NULL);
pthread_join(id3,NULL);
return 0;
}