为什么没有奇怪的 Windows 进程 ID?

Pet*_*orf 162 windows process

在 Windows 中有许多方法可以检查进程 ID。

例如,使用 PowerShell 命令:

ps | select Id, ProcessName  | Sort Id | ft -AutoSize
Run Code Online (Sandbox Code Playgroud)

我们看到以下输出:

  Id ProcessName         
  -- -----------         
   0 Idle                
   4 System              
 264 svchost             
 388 smss                
 476 csrss               
 536 wininit             
 580 winlogon                      
 620 services            
 628 lsass                          
 728 svchost             
 828 dwm                                     
1060 chrome              
1080 rundll32            
1148 vmms                                        
1620 spoolsv                                                
2912 taskhostex          
3020 explorer       
...     
Run Code Online (Sandbox Code Playgroud)

所有进程 ID 都是偶数,而且它们都是4 的倍数

在任何基于 Windows NT 的 Windows 版本上都没有奇怪的进程 ID。

这是什么原因?

Dav*_*ill 168

“为什么没有奇怪的 Windows 进程 ID?”

分配内核句柄的相同代码也用于分配进程和线程 ID。由于内核句柄是 4 的倍数,因此进程和线程 ID 也是如此。


为什么进程和线程 ID 是四的倍数?

在基于 Windows NT 的操作系统上,进程和线程 ID 碰巧总是四的倍数。这只是巧合吗?

是的,这只是一个巧合,您不应该依赖它,因为它不是编程合同的一部分。例如,Windows 95 进程和线程 ID 并不总是四的倍数。(相比之下,内核句柄始终是 4 的倍数的原因是规范的一部分,并且在可预见的未来将得到保证。)

作为代码重用的副作用,进程和线程 ID 是 4 的倍数。分配内核句柄的相同代码也用于分配进程和线程 ID。由于内核句柄是 4 的倍数,因此进程和线程 ID 也是如此。这是一个实现细节,所以不要编写依赖它的代码。我只是告诉你满足你的好奇心。

Source为什么进程和线程 ID 是四的倍数?


为什么内核句柄总是四的倍数?

不太为人所知的是,内核 HANDLE 的底部两位总是为零;换句话说,它们的数值总是 4 的倍数。请注意,这仅适用于内核句柄;它不适用于伪句柄或任何其他类型的句柄(用户句柄、GDI 句柄、多媒体句柄...)内核句柄是您可以传递给 CloseHandle 函数的东西。

底部两位的可用性隐藏在 ntdef.h 头文件中:

//
// Low order two bits of a handle are ignored by the system and available
// for use by application code as tag bits.  The remaining bits are opaque
// and used to store a serial number and table index.
//

#define OBJ_HANDLE_TAGBITS  0x00000003L
Run Code Online (Sandbox Code Playgroud)

GetQueuedCompletionStatus 函数暗示至少内核句柄的底部位始终为零,这表明您可以设置事件句柄的底部位以抑制完成端口通知。为了使其工作,底部位通常必须为零。

此信息对大多数应用程序编写者没有用,他们应继续将 HANDLE 视为不透明值。对标记位感兴趣的人是那些正在实现低级类库或将内核对象包装在更大框架中的人。

来源为什么内核句柄总是四的倍数?


进一步阅读


  • @BlueRaja:内核句柄是四的倍数,这是契约性的,所以你可以依赖它;*process ids*(与进程句柄*不*相同),相反,*恰好*是四的倍数,但这只是一个实现细节,所以你不应该依赖它。 (39认同)
  • @BlueRaja 我想 Raymond 会告诉你,无论是谁写的文档都是通过 *内核色眼镜* 看世界的,因此只提到内核句柄而不是其他类型的句柄。 (7认同)
  • 一个引用说*“你不应该依赖它,因为它不是编程合同的一部分,”*但接下来的声明 ntdef.h 说这些位 *“可供应用程序代码用作标记位。”*公共头文件中的文档与您所能获得的 _“编程合同”_ 非常接近,因此第一个声明是不正确的。 (3认同)
  • @BlueRaja,“不太为人所知的是**内核句柄的底部两位始终为零;换句话说,它们的数值始终是 4 的倍数。**” ntdef.h 中的代码适用于其他类型句柄(用户句柄、GDI 句柄、多媒体句柄...) (2认同)