1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 《Windows via C/C++》学习笔记 —— “线程同步”之“检测死锁”

《Windows via C/C++》学习笔记 —— “线程同步”之“检测死锁”

时间:2021-04-16 21:47:07

相关推荐

《Windows via C/C++》学习笔记 —— “线程同步”之“检测死锁”

本来这篇内容在书中是在“其他线程同步函数”这一节中的。这节中介绍了另外的几个等待函数,比如WaitForInputIdle、MsgWaitForMultipleObjects、WaitForDebugEvent,感觉用途不大,只有SignalObjectAndWait这个函数用途比较大,该函数笔者已经在前面的“等待函数”这一篇中写过了。

本篇主要讨论这本书新增加的内容,就是Windows Vista中提供的调查死锁的方法。

在Windows Vista中,提供了用来“检测线程死锁”的一组API,Jeffrey Richter先生在书中将其称为“Wait Chain Traversal”(WCT)API。查看了网上的翻译,叫做“等待链遍历”API函数,我也不知道这么翻译是否正确或权威,就姑且这么叫着吧,下面简称为WCT。

WCT函数允许你列出“锁”,并检测死锁,无论是单个进程的,还是跨进程的。Windows对以下线程同步机制的锁保持着跟踪:

需要注意的是,读写锁(SRWLock)同步机制没有被WPC所跟踪,另外某些内核对象,比如事件内核对象、信号量、等待定时器没有被跟踪。

本书举了一个例子来演示了WPC函数的使用。本人总结了下,主要通过以下几个步骤来实现死锁的检测:

1、打开等待链:使用OpenThreadWaitChainSession函数

2、如果需要检测COM的话:使用RegisterWaitChainCOMCallback函数

3、取得等待链信息:使用GetThreadWaitChain函数

4、关闭等待链:使用CloseThreadWaitChainSession函数

首先,介绍一下OpenThreadWaitChainSession函数:

HWCTOpenThreadWaitChainSession(

DWORDdwFlags,//0表示同步,WCT_ASYNC_OPEN_FLAG表示异步

PWAITCHAINCALLBACKcallback);//异步的话要设置该回调函数指针

该函数成功,返回一个HWCT类型的句柄,该句柄要传递给CloseThreadWaitChainSession函数,在最后释放。如果失败,该函数返回NULL。

一般地,您总是希望从中调用RegisterWaitChainCOMCallback函数以注册 CoGetCallState和CoGetActivationState这两个COM函数,以便WCT能够报告 COM所有权信息,由于并未记录这些函数,您需要从ole32.dll通过GetProcAddress 获得这些函数。本人认为,在您对WCT API进行初始化以查找COM死锁时,WCT API 应自动处理这种细小问题。

VOIDWINAPIRegisterWaitChainCOMCallback(

__inPCOGETCALLSTATECallStateCallback,//CoGetCallState函数地址

__inPCOGETACTIVATIONSTATE

ActivationStateCallback//CoGetActivationState函数地址

);

你可以使用如下代码这样使用RegisterWaitChainCOMCallback函数:

PCOGETCALLSTATECallStateCallback;//函数指针

PCOGETACTIVATIONSTATEActivationStateCallback;//函数指针

HMODULEhOLE32DLL=LoadLibrary(TEXT("OLE32.DLL"));//加载OLE32.DLL

//从ole32.dll中取得函数地址

CallStateCallback=(PCOGETCALLSTATE)

GetProcAddress(_hOLE32DLL,"CoGetCallState");

ActivationStateCallback=(PCOGETACTIVATIONSTATE)

GetProcAddress(_hOLE32DLL,"CoGetActivationState");

//在等待链中注册COM函数

RegisterWaitChainCOMCallback(CallStateCallback,ActivationStateCallback);

下面,第3步,使用GetThreadWaitChain函数取得等待链信息:

BOOLWINAPIGetThreadWaitChain(

HWCThWctSession,//等待链句柄

DWORD_PTRpContext,//异步方法中回调函数的参数

DWORDdwFlags,//查询类型(位或组合)

DWORDTID,//要查询的线程的线程ID

PDWORDpNodeCount,//返回值,指明等待链中的结点个数

PWAITCHAIN_NODE_INFOpNodeInfoArray,//返回值,等待链结点信息

LPBOOLpbIsCycle//返回值,TURE表示死锁

);

pNodeCount参数如果返回的DWORD数据值为0,表明一个问题产生了,比如拒绝访问。这个时候可以调用GetLastError取得错误信息。

这个函数中,pNodeInfoArray函数是一个WAITCHAIN_NODE_INFO结构的指针,该结构如下:

typedefstruct_WAITCHAIN_NODE_INFO

{

WCT_OBJECT_TYPEObjectType;//结点对象类型

WCT_OBJECT_STATUSObjectStatus;//结点对象状态

union{

struct{

WCHARObjectName[WCT_OBJNAME_LENGTH];

LARGE_INTEGERTimeout;//Notimplementedinv1

BOOLAlertable;//Notimplementedinv1

}LockObject;

struct{

DWORDProcessId;

DWORDThreadId;

DWORDWaitTime;

DWORDContextSwitches;

}ThreadObject;

};

}WAITCHAIN_NODE_INFO,*PWAITCHAIN_NODE_INFO;

该结构中的ObjectTyped成员,指明了当前等待链中的结点类型,ObjectStatus指明了当前该结点对象的状态,两者具体取值就看MSDN或本书吧。如果这个结点类型是一个“阻塞”状态的线程,即ObjectTyped为WctThreadType的话,内部的ThreadObject成员即有效。

最后,不要忘记调用CloseThreadWaitChainSession关闭WCT句柄。当然,如果用LoadLibrary函数加载了OLE23.dll文件的话,也要记得FreeLibrary函数来释放。

可以使用如下代码处理等待链中的结点:

HWCThWCTSession=OpenThreadWaitChainSession(0,NULL);

if(hWCTSession==NULL)

return0;

//两个COM的函数指针

PCOGETCALLSTATECallStateCallback;

PCOGETACTIVATIONSTATEActivationStateCallback;

HMODULEhOLE32DLL=LoadLibrary(TEXT("OLE32.DLL"));//加载OLE32.DLL

if(hOLE32DLL==NULL)

return0;

//从ole32.dll中取得两个函数的地址

CallStateCallback=(PCOGETCALLSTATE)

GetProcAddress(_hOLE32DLL,"CoGetCallState");

ActivationStateCallback=(PCOGETACTIVATIONSTATE)

GetProcAddress(_hOLE32DLL,"CoGetActivationState");

//注册COM函数,使得WCT可以报告COM相关事件

RegisterWaitChainCOMCallback(CallStateCallback,ActivationStateCallback);

//在你需要处理的线程中:

DWORDdwNodesInChain=0;//链中的结点个数

BOOLbDeadlock=FALSE;//线程是否存在死锁

WAITCHAIN_NODE_INFOchain[WCT_MAX_NODE_COUNT];//WCT节点结构数组

//取得等待链信息,并判断是否正确,TID为线程ID

if(!GetThreadWaitChain(hWCTSession,NULL,WCTP_GETINFO_ALL_FLAGS,

TID,&dwNodesInChain,chain,&bDeadlock))

{

//函数调用失败,在此处理

//

return0;

}

//开始处理等待链

dwNodesInChain=min(dwNodesInChain,WCT_MAX_NODE_COUNT);

if(dwNodesInChain==0)//结点个数为0,可以调用GetLastError处理

return0;

//可以在此处理本线程有关的等待链信息

if(bDeadlock)

//表明线程ID为TID的线程存在死锁

//处理每个链中的节点

for(DWORDcurrent=0;current<dwNodesInChain;++current)

{

//在此处理练中每个结点信息

//

}

FreeLibrary(hOLE32DLL);//释放COM模块

CloseThreadWaitChainSession(hWCTSession);//关闭WCT

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。