当OwningThread表示线程ID时,它为什么是HANDLE类型的CRITICAL_SECTION的成员

Why is the OwningThread member of CRITICAL_SECTION of type HANDLE, when it is denoting the thread ID?

本文关键字:类型 HANDLE CRITICAL 成员 SECTION 为什么 线程 表示 OwningThread ID      更新时间:2023-10-16

我试图为CRITICAL_SECTION解锁代码添加一些调试检查,并尝试了以下操作:

...
if (m_pCritSect) {
ASSERT(m_pCritSect->OwningThread == GetCurrentThreadId());
LeaveCriticalSection(m_pCritSect);
}
}

通过调试CRITICAL_SECTIONS(使用VS 2005,主要在WindowsXP上),我"知道"OwningThread(winnt.h中定义的RTL_CRITICAL_SECTION结构的成员)的值是持有锁的线程的thID的值。

然而,线程ID由DWORD(unsigned long的typedef)值表示,而此变量的类型为HANDLE(void*的typedef),需要reinterpret_cast,使用basetsd.h中的HandleToULong宏才能使上述代码工作。

甚至MSDN文档也声明:

当第一个线程调用EnterCriticalSection例程时,(…)OwningThread将成为调用方的线程ID。

那么,为什么这被定义为HANDLE呢?


编辑注意:我发现了一个声明,其中海报表明HANDLE/DWORD Id不匹配是一些Windows内部的一些已知错误功能。也许这里也有这种情况:

GetCurrentThreadId返回一个DWORD,我在消息PsLookupThreadByThreadId获取HANDLE中的线程Id。。。…

这是一个已知的Windows API错误(在我与相关的筛选器管理器DEV,如filter中所示由于I/O Manager API问题,管理器也是如此。)只要你没有超过5亿左右的线程和进程(它们使用一个共享句柄表),你会没事的。也许到那时这是一个真正的问题,我们将运行一些不同的东西。[RE:威胁要处理64位?,08年8月8日14:21,Tony Mason]

SDK中任何名称以RTL或RTL开头的标识符都是运行时层的代码或声明,是将有充分文档记录的Winapi与无文档记录的本机操作系统api结合在一起的粘合剂。winapi是铁板一块的,本机操作系统随着每个Windows版本的发布而发生重大变化。不可避免的是,胶水也会发生变化。

winapi是有文档的层,本机操作系统是没有文档的。运行时层也没有文档,但随着时间的推移,它的一部分被暴露了出来。要么是因为它重新填充了winapi中缺少的功能。或者,在这种情况下,因为它对解决问题真正有用。然而,这样做的一个核心问题是,一旦声明被披露,微软就再也无法改变它了。因为这样做会破坏现有的程序,给客户带来很大的负担。

毫无疑问,ThreadOwner字段曾经在以前的Windows版本中真正拥有线程的句柄。请注意LockSemaphore是如何误导的,它实际上是一个自动重置事件。太迟了,修不好了,猫出包了。

我认为主要原因是它是一个实现细节。如果在历史上的某个时候,它真的是一个把手或类似的东西,我不会感到惊讶。

此外,我强烈建议不要在生产代码中使用内部成员,我并不是唯一一个这样做的人。如果仔细观察,同步API使用CRITICAL_SECTION,而不是RTL_CRITICAL_SECTION(类型定义为CRITICAL_SECTION)

存储在OwningThread成员中的值取自线程信息块的CLIENT_ID部分。在CLIENT_ID中,它被建模为PVOID,这可能是它在CRITICAL_SECTION:中以相同方式建模的原因

typedef struct _CLIENT_ID
{
PVOID UniqueProcess;
PVOID UniqueThread;
} CLIENT_ID, *PCLIENT_ID;