unix线程死锁概念与解决
线程死锁的两种方式
死锁概念:线程死锁指的是线程需要使用的公共资源一直被其他线程占用,导致该线程一直处于阻塞状态,无法继续执行。
那么造成死锁的情况主要有以下两种情况。
1.线程上锁,执行完具体逻辑之后,忘记解锁。或者上了多把锁mutex,上锁num大于解锁的num。
2.对于多个线程,同时执行,线程A成功申请锁1,线程B成功申请锁2,都互相等待对方将锁打开,然后解锁自己成功加上的锁,这就是第二种死锁情况。
实例一,针对情1,下面看下具体实例。
#include<stdio.h>
#include<pthread.h>
//创建并初始化互斥锁
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_func(void *arg) {
int islock;
//为线程加锁
islock = pthread_mutex_lock(&myMutex);
if (islock == 0) {
printf("线程 %u 已加锁\n", pthread_self());
}
return 0;
}
int main() {
int flag;
int i;
//创建 4 个线程
pthread_t tids[4];
for (i = 0; i < 4; i++)
{
flag = pthread_create(&tids[i], NULL, thread_func, NULL);
if (flag == 0) {
printf("线程 %u 创建完成\n",tids[i]);
}
}
for(i = 0; i<4;i++){
pthread_join(tids[i], NULL);
printf("线程 %u 执行完成\n",tids[i]);
}
return 0;
}
我的程序编译后的执行情况:
线程 1831481344 创建完成
线程 1831481344 已加锁
线程 1832054784 创建完成
线程 1832628224 创建完成
线程 1833201664 创建完成
线程 1831481344 执行完成
这就造成了一种线程死锁的情况,如果没线程死锁的话,我们的期望输出应该如下:
线程 1805021184 创建完成
线程 1805594624 创建完成
线程 1806168064 创建完成
线程 1806741504 创建完成
线程 1805021184 已加锁
线程 1805594624 已加锁
线程 1806168064 已加锁
线程 1806741504 已加锁
线程 1805021184 执行完成
线程 1805594624 执行完成
线程 1806168064 执行完成
如何修复:只需在thread_func这个线程执行逻辑接口中加入pthread_mutex_unlock(&my_Mutex)即可。
实例二,针对情况2,下面看具体实例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
void *func1(void *args)
{
pthread_mutex_lock(&mutex);
printf("t1 成功申请 mytex 锁\n");
sleep(2);
pthread_mutex_lock(&mutex2);
printf("t1 成功申请 mytex2 锁\n");
printf("%u is running\n",pthread_self());
pthread_mutex_unlock(&mutex);
printf("------%u done\n",pthread_self());
}
void *func2(void *args)
{
pthread_mutex_lock(&mutex2);
printf("t2 成功申请 mytex2 锁\n");
sleep(2);
pthread_mutex_lock(&mutex);
printf("t2 成功申请 mytex 锁\n");
printf("%u is running\n",pthread_self());
pthread_mutex_unlock(&mutex);
printf("------%u done\n",pthread_self());
}
int main()
{
int ret;
pthread_t t1;
pthread_t t2;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex2,NULL);
ret = pthread_create(&t1, NULL, func1, NULL);
if(ret != 0){
printf("create t1 fail\n");
}
ret = pthread_create(&t2, NULL, func2, NULL);
if(ret != 0){
printf("create t2 fail\n");
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex2);
return 0;
}
执行结果:
t1 成功申请 mytex 锁
t2 成功申请 mytex2 锁
这样卡住,无法继续向下执行。
如何解决:
可以将pthread_mutex_lock接口尝试替换为pthread_mutex_trylock,或者是修改代码部分逻辑。
本博客linux涉及到的一些线程知识
1.pthread_join(pthread_t thread, void **retval)
作用:以阻塞的方式等待thread指定的逻辑执行结束。
2.pthread_mutex_destroy(pthread_mutex_t *mp)
作用:释放用来存储互斥锁的空间,避免内存泄漏。
3.pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr)
作用:函数是以动态方式创建互斥锁的,参数attr指定了新建互斥锁的属性。如果参数attr为NULL,则使用默认的互斥锁属性,默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。
上一篇: 线程同步与死锁