我正在尝试为CRITICAL_SECTION解锁代码添加一些调试检查,我尝试了以下内容:
...
if (m_pCritSect) {
ASSERT(m_pCritSect->OwningThread == GetCurrentThreadId());
LeaveCriticalSection(m_pCritSect);
}
}
从调试CRITICAL_SECTIONS(使用VS 2005,主要是在WindowsXP上)我“知道”OwningThread
(RTL_CRITICAL_SECTION
中定义的winnt.h
结构的成员)的值是值{持有锁的线程 ID 。
但是,线程ID由DWORD
(unsigned long
的typedef)值表示,而此变量的类型为HANDLE
(void*
的typedef),需要 a {{ 1}} 使用来自reinterpret_cast
的{{1}}宏来使上述代码生效。
即使是MSDN docs州:
当第一个线程调用EnterCriticalSection例程时,(...) OwningThread成为调用者的线程ID。
那么为什么这个被定义为HandleToULong
?
编辑注意:我发现a statement海报显示HANDLE / DWORD-Id不匹配是某些Windows内部的一些已知错误。所以也许这就是这种情况:
GetCurrentThreadId返回一个DWORD,我将其发送到内核中 信息。 PsLookupThreadByThreadId在一个HANDLE中获取线程Id,... ...
这是一个已知的Windows API错误(“已知”,因为我与之交谈过 关于此的相关过滤器管理器DEV,因为它显示在Filter中 管理器也是因为I / O Manager API问题。)只要你 没有超过五亿左右的线程和进程(他们 使用单个共享句柄表,你会没事的。也许到了时候 这是一个真正的问题,我们将运行不同的东西。 [ RE:ThreadId to HANDLE for 64 bit?,08 Aug 08 14:21,Tony Mason]
答案 0 :(得分:8)
SDK中名称以RTL或Rtl开头的任何标识符都是代码或声明,它们是运行时层的一部分,是将记录良好的Winapi与未记录的本机操作系统api结合在一起的粘合剂。 winapi是一成不变的,每个Windows版本的本机操作系统都会发生巨大变化。不可避免地,胶水也会发生变化。
winapi是记录层,本机操作系统没有记录。运行时层也没有记录,但随着时间的推移,部分内容被揭示出来。无论是因为它回填了winapi中缺少的功能。或者,在这种情况下,因为真正有用的解决问题。然而,这样做的一个核心问题是,一旦宣布声明,微软就永远不会再改变它。因为这样做会破坏现有的程序,给客户带来很大的负担。
当然,ThreadOwner字段曾经真正拥有以前Windows版本中线程的句柄。注意LockSemaphore是如何误导的,它实际上是一个自动重置事件。为了解决这个问题太晚了,这只猫已经不在了。
答案 1 :(得分:4)
我认为主要原因是它是一个实现细节。如果在历史上有一段时间它真的是一个手柄或类似的东西,我不会感到惊讶。
此外,我强烈建议不要在生产代码中使用内部成员,I am not alone。如果仔细观察,同步API使用CRITICAL_SECTION
,您将无法将其记录为MSDN中的结构,而不是RTL_CRITICAL_SECTION(其类型定义为CRITICAL_SECTION)
OwningThread
成员中存储的值取自Thread Information Block的CLIENT_ID部分。在CLIENT_ID中,它建模为PVOID,这可能是它在CRITICAL_SECTION中以相同方式建模的原因:
typedef struct _CLIENT_ID
{
PVOID UniqueProcess;
PVOID UniqueThread;
} CLIENT_ID, *PCLIENT_ID;