互斥锁的作用与操作
互斥锁
互斥锁是为了解决在多线程访问共享资源时,多个线程同时对共享资源操作产生的冲突而提出的一种解决方法,在执行时,哪个线程持有互斥锁,并对共享资源进行加锁后,才能对共享资源进行操作,此时其它线程不能对共享资源进行操作。只有在持有锁的线程将锁解锁释放后,其它线程才能进行抢锁加锁操作。
主要作用就是用来解决多线程对共享资源的竞争问题。
pthread_mutex_init互斥锁初始化
原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
参数:
mutex:互斥锁变量地址(互斥锁资源)
attr:属性信息
返回:
成功:1
失败:errorr(错误号码)
pthread_mutex_lock上锁
原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:
mutex:互斥锁变量地址(互斥锁资源)
返回:
成功:1
失败:errorr(错误号码)
pthread_mutex_unlock解锁
原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:
mutex:互斥锁变量地址(互斥锁资源)
返回:
成功:1
失败:errorr(错误号码)
pthread_mutex_destroy销毁互斥锁
原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:
mutex:互斥锁变量地址(互斥锁资源)
返回:
成功:1
失败:errorr(错误号码)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex; //定义一个锁资源变量(传参容易出问题)
void *func(void *arg);
int main(int argc, char **argv)
{
int status = pthread_mutex_init(&mutex,NULL); //初始化互斥锁
pthread_t thread;
pthread_create (&thread, NULL,func,NULL);//创建线程
while(1) //循环上锁
{
int i = 0;
pthread_mutex_lock(&mutex);//上锁
printf("11111我上锁了\n");
while(1)
{
i++;
if(i == 200)
{
printf("i = %d\n",i);
printf("11111我解锁了\n");
pthread_mutex_unlock(&mutex); //解锁
break;
}
}
sleep(1); //防止解锁完后立即上锁
}
return 0;
}
void *func(void *arg)
{
pthread_t id = pthread_self(); //获取当前线程id
pthread_detach(id); //设置自我分离
while(1) //循环上锁
{
int k = 0;
pthread_mutex_lock(&mutex);//上锁
printf("22222我上锁了\n");
while(1)
{
k++;
if(k == 200)
{
printf("k = %d\n",k);
printf("22222我解锁了\n");
pthread_mutex_unlock(&mutex); //解锁
break;
}
}
sleep(1);
}
}
死锁
产生死锁的原因
当进程需要以独占的方式访问资源时,可能会发生死锁(Deadlock)。死锁是指两个或以上进程因竞争临界资源而造成的一种僵局,即一个进程等待一个已经被占用且永不释放的资源。若无外力作用,这些进程都无法向前推进。
产生死锁的四个条件
互斥条件
涉及的资源是非共享的,即一次只能有一个进程使用。如果有另一个进程申请该资源,那么申请进程必须等待,直到该资源被释放。
不剥夺条件(非抢占)
进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自行释放。
占有并等待(部分分配)
进程每次申请它所需要的一部分资源。在等待一新资源的同时,进程继续占用已分配到的资源。
环路条件(循环等待)
存在一种进程收尾相接的循环链,链中每个进程都在等待下一个进程所持有的资源,造成这组进程处于永远等待状态。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立。反之,上述条件只要有一个不满足,就不会发生死锁。所以要避免发生死锁,只需要破坏其必要条件。
线程中防止死锁
pthread_cleanup_push压栈线程处理函数
原型:
void pthread_cleanup_push(void (*routine)(void *), void *arg)
功能
函数压栈(线程清理函数)
参数:
routine:线程的取消处理函数
arg:线程的取消处理函数的参数
pthread_cleanup_pop压栈线程处理函数
原型:
void pthread_cleanup_pop(int execute)
功能
该函数在程序异常终止时会调用pthread_cleanup_push()时压入清理函数栈,采用先入后出的栈结构管理
参数:
execute:
写0:弹栈线程的取消处理函数,但不执行该函数
非0:弹栈线程的取消处理函数,并执行该函数
这个参数并不影响异常终止时清理函数的执行
示例代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
//定义互斥锁
pthread_mutex_t mutex;
void *routine(void *arg);
void function(void *arg);
int main()
{
pthread_mutex_init(&mutex, NULL);//初始化互斥锁
pthread_t id;//定义一个线程ID号
pthread_create(&id, NULL, routine, NULL);//创建线程 ---》线程id号保存地址
while(1) //循环上锁
{
pthread_mutex_lock(&mutex); //上锁
printf("1 我上锁啦!!\n");
char buf[128];
while(1)
{
printf("线程1:");
scanf("%s", buf);
if(!strcmp(buf,"A"))
{
break;
}
}
printf("1 我解锁啦!!\n");
pthread_mutex_unlock(&mutex);//解锁
sleep(1);
}
pthread_mutex_destroy(&mutex);//销毁互斥锁
pthread_exit(NULL);
}
//线程函数
void *routine(void *arg)
{
pthread_t id = pthread_self();
while(1)
{
pthread_mutex_lock(&mutex);//上锁
pthread_cleanup_push(function,NULL); //函数压栈(线程清理函数)
printf("2 我上锁啦!!\n");
char buf[128];
while(1)
{
printf("线程2:");
scanf("%s", buf);
if(!strcmp(buf,"B"))
{
break;
}
if(!strcmp(buf,"Z"))
{
pthread_cancel(id); //取消线程
}
}
printf("2 我解锁啦!!\n");
pthread_mutex_unlock(&mutex); //解锁
pthread_cleanup_pop(0); //正常退出不执行线程清理函数
sleep(1);
}
return NULL;
}
//清理函数(防止死锁)
void function(void *arg)
{
printf("哟,咋了\n");
//解锁(防止线程异常结束尔造成的死锁)
pthread_mutex_unlock(&mutex);
}