互斥锁和死锁
互斥锁的作用与操作
互斥锁
互斥锁是为了解决在多线程访问共享资源时,多个线程同时对共享资源操作产生的冲突而提出的一种解决方法,在执行时,哪个线程持有互斥锁,并对共享资源进行加锁后,才能对共享资源进行操作,此时其它线程不能对共享资源进行操作。只有在持有锁的线程将锁解锁释放后,其它线程才能进行抢锁加锁操作。
主要作用就是用来解决多线程对共享资源的竞争问题。
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
#include
#include 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(); //获取当前线程idpthread_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
#include
#include
#include
#include
#include //定义互斥锁
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);}

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
