面试题答案
一键面试使用工具检测死锁
- Valgrind:
- 安装:在大多数Linux发行版上,可以通过包管理器安装Valgrind,如在Ubuntu上使用
sudo apt - get install valgrind
。 - 使用:运行程序时带上
valgrind --tool = helgrind
参数,例如valgrind --tool = helgrind./your_program
。Helgrind是Valgrind的一个工具,专门用于检测多线程程序中的竞争条件和死锁。它会分析程序的线程交互,并报告潜在的问题。
- 安装:在大多数Linux发行版上,可以通过包管理器安装Valgrind,如在Ubuntu上使用
代码层面优化多线程性能
- 优化锁的粒度:
- 含义:锁的粒度指的是锁所保护的共享资源的范围。
- 优化方式:尽量减小锁的粒度,只对真正需要保护的共享资源加锁。例如,如果有一个大型的数据结构,而不同的线程只访问其中的不同部分,可以为每个部分分别设置锁,而不是对整个数据结构加一把大锁。这样可以提高并发度,减少线程等待锁的时间。
- 优化锁的获取顺序:
- 含义:多个线程获取多个锁时,按照一致的顺序获取锁可以避免死锁。
- 优化方式:为所有需要获取的锁分配一个全局的唯一编号,所有线程都按照编号从小到大的顺序获取锁。例如,有锁A、锁B、锁C,编号分别为1、2、3,那么所有线程都先获取锁A,再获取锁B,最后获取锁C。
可能导致死锁的代码示例
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
void *thread1(void *arg) {
pthread_mutex_lock(&mutex1);
printf("Thread 1 locked mutex1\n");
pthread_mutex_lock(&mutex2);
printf("Thread 1 locked mutex2\n");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
void *thread2(void *arg) {
pthread_mutex_lock(&mutex2);
printf("Thread 2 locked mutex2\n");
pthread_mutex_lock(&mutex1);
printf("Thread 2 locked mutex1\n");
pthread_mutex_unlock(&mutex1);
pthread_mutex_unlock(&mutex2);
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread1, NULL);
pthread_create(&tid2, NULL, thread2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
在这个示例中,thread1
先获取mutex1
再获取mutex2
,而thread2
先获取mutex2
再获取mutex1
,如果thread1
获取了mutex1
,thread2
获取了mutex2
,就会发生死锁。
修改代码以避免死锁
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
void *thread1(void *arg) {
pthread_mutex_lock(&mutex1);
printf("Thread 1 locked mutex1\n");
pthread_mutex_lock(&mutex2);
printf("Thread 1 locked mutex2\n");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
void *thread2(void *arg) {
pthread_mutex_lock(&mutex1);
printf("Thread 2 locked mutex1\n");
pthread_mutex_lock(&mutex2);
printf("Thread 2 locked mutex2\n");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
int main() {
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread1, NULL);
pthread_create(&tid2, NULL, thread2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}
修改后的代码,thread1
和thread2
都按照先获取mutex1
再获取mutex2
的顺序加锁,避免了死锁的发生。