什么是死锁
线程死锁一般是发生在多个线程的多个锁之间,比如线程A拥有临界区对象LockA的所有权,等待临界区对象LockB;线程B拥有临界区对象LockB的所有权,等待临界区对象LockA;由于两个线程间相互等待各自的锁,并且不释放,就会导致程序一直等待下去,发生死锁;
死锁伪代码
//线程A
EnterCriticalSection(&g_csLockA);
Sleep(10);
EnterCriticalSection(&g_csLockB);//等B
....
//对于释放顺序没有影响
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
//线程B
EnterCriticalSection(&g_csLockB);
Sleep(10);
EnterCriticalSection(&g_csLockA);//等A
....
//对于释放顺序没有影响
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
过分分析
比如线程A先获得时间片,线程A执行并获得LockA的所有权;sleep(10)之后,线程B获得时间片,线程B执行并获得LockB的所有权;
当线程A再次活动执行权,线程A会等待LockB的的所有权,同理线程B也还会等LockB的所有权;由于两者都不释放,程序会一致等待下去,发生了死锁;
解决死锁
在多线程编程中,为了避免发生这样的情况,可以有两种方法进行预防,这样可以避免死锁的发生;
- 加锁顺序一致
//线程A:先等锁A,再等锁B
EnterCriticalSection(&g_csLockA);
Sleep(10);
EnterCriticalSection(&g_csLockB);
....
//对于释放顺序没有影响
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
//线程B:也是先等锁A,再等锁B
EnterCriticalSection(&g_csLockA);
Sleep(10);
EnterCriticalSection(&g_csLockB);
....
//对于释放顺序没有影响
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
- 避免锁未释放的场景
//线程:
EnterCriticalSection(&g_csLockA);
Sleep(10);
EnterCriticalSection(&g_csLockB);
....
//对于释放顺序没有影响
LeaveCriticalSection(&g_csLockA);
....
return true;
.....
LeaveCriticalSection(&g_csLockB);
死锁实例
// MultiThread.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
//#include <windows.h>
#include <iostream>
#include <afxmt.h>
using namespace std;
int g_nIndex = 0;
const int nMaxCnt = 20;
CRITICAL_SECTION g_csLockA;
CRITICAL_SECTION g_csLockB;
DWORD WINAPI Thread1SynByCS(LPVOID lpParameter)
{
while (TRUE)
{
//先等锁A,再等锁B,发生死锁,程序一直等待,直至主线程结束
EnterCriticalSection(&g_csLockA);
Sleep(10);
EnterCriticalSection(&g_csLockB);
//关键代码段-begin
if (g_nIndex++ < nMaxCnt)
{
cout << "Index = "<< g_nIndex << " ";
cout << "Thread2 is runing" << endl;
//权限释放
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
}
else
{
//权限释放
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
//关键代码段-end
break;
}
}
return 0;
}
DWORD WINAPI Thread2SynByCS(LPVOID lpParameter)
{
while (TRUE)
{
//先等锁B,再等锁A,发生死锁,程序一直等待,直至主线程结束
EnterCriticalSection(&g_csLockB);
Sleep(10);
EnterCriticalSection(&g_csLockA);
//关键代码段-begin
if (g_nIndex++ < nMaxCnt)
{
cout << "Index = "<< g_nIndex << " ";
cout << "Thread2 is runing" << endl;
//权限释放
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
}
else
{
//权限释放
LeaveCriticalSection(&g_csLockA);
LeaveCriticalSection(&g_csLockB);
//关键代码段-end
break;
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hThread1 = NULL;
HANDLE hThread2 = NULL;
//初始化关键代码段对象
InitializeCriticalSection(&g_csLockA);
InitializeCriticalSection(&g_csLockB);
//创建新的线程
hThread1 = CreateThread(NULL,0,Thread1SynByCS,NULL,0,NULL);//立即执行
hThread2 = CreateThread(NULL,0,Thread2SynByCS,NULL,0,NULL);//立即执行
//无须对新线程设置优先级等操作,关闭之
//良好的编码习惯
CloseHandle(hThread1);
CloseHandle(hThread2);
Sleep(3000);
//删掉关键代码段对象,并删除系统资源
DeleteCriticalSection(&g_csLockA);
DeleteCriticalSection(&g_csLockB);
return 0;
}