本篇博客主要记录一下课堂上的几个小实验
死锁调试实验
下面主要通过不同工具来写本篇博客
先贴上实验代码
#include <unistd.h>
#include <pthread.h>
#include <string.h>
pthread_mutex_t mutexA = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexB = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexC = PTHREAD_MUTEX_INITIALIZER;
static int counterA = 0;
static int counterB = 0;
int func1()
{
pthread_mutex_lock(&mutexA);
++counterA;
sleep(1);
pthread_mutex_lock(&mutexB);
++counterB;
pthread_mutex_unlock(&mutexB);
pthread_mutex_unlock(&mutexA);
return counterA;
}
int func2()
{
pthread_mutex_lock(&mutexB);
++counterB;
sleep(1);
pthread_mutex_lock(&mutexA);
++counterA;
pthread_mutex_unlock(&mutexA);
pthread_mutex_unlock(&mutexB);
return counterB;
}
void* start_routine1(void* arg)
{
while (1)
{
int iRetValue = func1();
if (iRetValue == 100000)
{
pthread_exit(NULL);
}
}
}
void* start_routine2(void* arg)
{
while (1)
{
int iRetValue = func2();
if (iRetValue == 100000)
{
pthread_exit(NULL);
}
}
}
void* start_routine(void* arg)
{
while (1)
{
sleep(1);
char szBuf[128];
memset(szBuf, 0, sizeof(szBuf));
strcpy(szBuf, (char*)arg);
}
}
int main()
{
pthread_t tid[4];
if (pthread_create(&tid[0], NULL, &start_routine1, NULL) != 0)
{
_exit(1);
}
if (pthread_create(&tid[1], NULL, &start_routine2, NULL) != 0)
{
_exit(1);
}
if (pthread_create(&tid[2], NULL, &start_routine, (char*)"thread3") != 0)
{
_exit(1);
}
if (pthread_create(&tid[3], NULL, &start_routine, (char*)"thread3") != 0)
{
_exit(1);
}
sleep(5);
//pthread_cancel(tid[0]);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_join(tid[2], NULL);
pthread_join(tid[3], NULL);
pthread_mutex_destroy(&mutexA);
pthread_mutex_destroy(&mutexB);
pthread_mutex_destroy(&mutexC);
return 0;
}
pstack
-
使用pstack命令,可以查看正在运行的进程的调用栈
需要注意的是,在我下载完成pstack的时候遇到了该脚本文件中出现乱码的问题
- pstack 的结果
从如下可以看到thread3 和thread2 拿到了两个mutexA 和mutexB 然后两个线程解锁时形成死锁
GDB调试
下图是使用gdb来进行调式的,因为pstack是对gdb的封装,所以结果相同
varlgrind
可以很直观的看到thread3,thread2两线程发生了锁的争抢,能够很快定位问题