面试题答案
一键面试死锁产生原因
在多线程数据共享场景下,死锁产生的原因主要有以下几点:
- 互斥条件:每个锁在同一时间只能被一个线程持有。
- 占有并等待:线程在持有一个锁的同时,等待获取其他锁。
- 不可剥夺:锁不能被强制从持有它的线程中夺走。
- 循环等待:线程之间形成一个环形的等待链,每个线程都在等待下一个线程持有的锁。
可能导致死锁的操作顺序
对于两个线程T1和T2,以及两把锁L1和L2,如果按照以下顺序操作可能导致死锁:
- 线程T1:获取锁L1。
- 线程T2:获取锁L2。
- 线程T1:尝试获取锁L2,但此时锁L2被线程T2持有,线程T1进入等待状态。
- 线程T2:尝试获取锁L1,但此时锁L1被线程T1持有,线程T2进入等待状态。 这样就形成了循环等待,导致死锁。
避免死锁的方法
- 按顺序获取锁:所有线程都按照相同的顺序获取锁,例如都先获取L1,再获取L2。
- 超时机制:设置获取锁的超时时间,如果在规定时间内没有获取到锁,则释放已经获取的锁,并进行相应处理。
- 资源分配图算法:通过算法检测是否会出现死锁,如果会则不进行资源分配。
避免死锁的代码结构示例(按顺序获取锁)
#include <pthread.h>
#include <stdio.h>
// 定义两把锁
pthread_mutex_t L1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t L2 = PTHREAD_MUTEX_INITIALIZER;
// 线程1的执行函数
void* thread1(void* arg) {
// 按顺序获取锁
pthread_mutex_lock(&L1);
printf("Thread 1 acquired L1\n");
pthread_mutex_lock(&L2);
printf("Thread 1 acquired L2\n");
// 操作共享数据
// 释放锁
pthread_mutex_unlock(&L2);
pthread_mutex_unlock(&L1);
return NULL;
}
// 线程2的执行函数
void* thread2(void* arg) {
// 按顺序获取锁
pthread_mutex_lock(&L1);
printf("Thread 2 acquired L1\n");
pthread_mutex_lock(&L2);
printf("Thread 2 acquired L2\n");
// 操作共享数据
// 释放锁
pthread_mutex_unlock(&L2);
pthread_mutex_unlock(&L1);
return NULL;
}
int main() {
pthread_t t1, t2;
// 创建线程1
if (pthread_create(&t1, NULL, thread1, NULL) != 0) {
printf("\n ERROR creating thread 1");
return 1;
}
// 创建线程2
if (pthread_create(&t2, NULL, thread2, NULL) != 0) {
printf("\n ERROR creating thread 2");
return 1;
}
// 等待线程1和线程2结束
pthread_join(t1, NULL);
pthread_join(t2, NULL);
// 销毁锁
pthread_mutex_destroy(&L1);
pthread_mutex_destroy(&L2);
return 0;
}
在上述代码中,两个线程都按照先获取L1
,再获取L2
的顺序进行操作,从而避免了死锁的发生。