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